Commit aecae396 aecae396938a1a5365c4889dba35c58f0d87a4bd by Alain Magloire

New file.

1 parent 9f739684
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Library Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 /* Notes:
19 First draft: Alain Magloire.
20
21 */
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26
27 #include <errno.h>
28 #include <string.h>
29 #include <stdlib.h>
30
31 #include <filter0.h>
32 #include <mailutils/iterator.h>
33
34 static void
35 filter_destroy (stream_t stream)
36 {
37 filter_t filter = stream_get_owner (stream);
38 if (filter->_destroy)
39 filter->_destroy (filter);
40 if (filter->property)
41 property_destroy (&(filter->property), filter);
42 free (filter);
43 }
44
45 static int
46 filter_read (stream_t stream, char *buffer, size_t buflen, off_t offset,
47 size_t *nbytes)
48 {
49 filter_t filter = stream_get_owner (stream);
50 if (filter->_read && (filter->direction & MU_STREAM_READ
51 || filter->direction & MU_STREAM_RDWR))
52 return filter->_read (filter, buffer, buflen, offset, nbytes);
53 return stream_read (filter->stream, buffer, buflen, offset, nbytes);
54 }
55
56 static int
57 filter_readline (stream_t stream, char *buffer, size_t buflen,
58 off_t offset, size_t *nbytes)
59 {
60 filter_t filter = stream_get_owner (stream);
61 if (filter->_readline && (filter->direction & MU_STREAM_READ
62 || filter->direction & MU_STREAM_RDWR))
63 return filter->_readline (filter, buffer, buflen, offset, nbytes);
64 return stream_readline (filter->stream, buffer, buflen, offset, nbytes);
65 }
66
67 static int
68 filter_write (stream_t stream, const char *buffer, size_t buflen,
69 off_t offset, size_t *nbytes)
70 {
71 filter_t filter = stream_get_owner (stream);
72 if (filter->_write && (filter->direction & MU_STREAM_WRITE
73 || filter->direction & MU_STREAM_RDWR))
74 return filter->_write (filter, buffer, buflen, offset, nbytes);
75 return stream_write (filter->stream, buffer, buflen, offset, nbytes);
76 }
77
78 static int
79 filter_open (stream_t stream, const char *filename, int port, int flags)
80 {
81 filter_t filter = stream_get_owner (stream);
82 stream_set_flags (stream, flags);
83 return stream_open (filter->stream, filename, port, flags);
84 }
85
86 static int
87 filter_truncate (stream_t stream, off_t len)
88 {
89 filter_t filter = stream_get_owner (stream);
90 return stream_truncate (filter->stream, len);
91 }
92
93 static int
94 filter_size (stream_t stream, off_t *psize)
95 {
96 filter_t filter = stream_get_owner (stream);
97 return stream_size (filter->stream, psize);
98 }
99
100 static int
101 filter_flush (stream_t stream)
102 {
103 filter_t filter = stream_get_owner(stream);
104 return stream_flush (filter->stream);
105 }
106
107 static int
108 filter_get_fd (stream_t stream, int *pfd)
109 {
110 filter_t filter = stream_get_owner (stream);
111 return stream_get_fd (filter->stream, pfd);
112 }
113
114 static int
115 filter_close (stream_t stream)
116 {
117 filter_t filter = stream_get_owner (stream);
118 return stream_close (filter->stream);
119 }
120
121 static int
122 filter_property (property_t property, const char *key, const char *value)
123 {
124 filter_t filter = property_get_owner (property);
125 (void)key;
126 if (value)
127 {
128 if (strcasecmp (value, "READ") == 0)
129 {
130 filter->direction = MU_STREAM_READ;
131 }
132 else if (strcasecmp (value, "WRITE") == 0)
133 {
134 filter->direction = MU_STREAM_WRITE;
135 }
136 else if (strcasecmp (value, "RDWR") == 0)
137 {
138 filter->direction = MU_STREAM_RDWR;
139 }
140 }
141 return 0;
142 }
143
144 /* NOTE: We will leak here since the monitor of the filter will never
145 be release. That's ok we can leave with this, it's only done once. */
146 static list_t filter_list;
147 struct _monitor filter_monitor = MU_MONITOR_INITIALIZER;
148
149 int
150 filter_get_list (list_t *plist)
151 {
152 if (plist == NULL)
153 return EINVAL;
154 monitor_wrlock (&filter_monitor);
155 if (filter_list == NULL)
156 {
157 int status = list_create (&filter_list);
158 if (status != 0)
159 return status;
160 /* Default filters. */
161 list_append (filter_list, base64_filter);
162 list_append (filter_list, qp_filter);
163 list_append (filter_list, binary_filter);
164 list_append (filter_list, bit8_filter);
165 list_append (filter_list, bit7_filter);
166 list_append (filter_list, rfc822_filter);
167 /* FIXME: add the default encodings? */
168 }
169 *plist = filter_list;
170 monitor_unlock (&filter_monitor);
171 return 0;
172 }
173
174 int
175 filter_create (stream_t *pstream, stream_t stream, const char *name,
176 int type, int direction)
177 {
178 iterator_t iterator = NULL;
179 filter_record_t filter_record = NULL;
180 int (*f_init) __P ((filter_t)) = NULL;
181 int found = 0;
182 int status;
183 list_t list = NULL;
184
185 if (pstream == NULL || stream == NULL || name == NULL)
186 return EINVAL;
187
188 filter_get_list (&list);
189 status = iterator_create (&iterator, list);
190 if (status != 0)
191 return status;
192
193 for (iterator_first (iterator); !iterator_is_done (iterator);
194 iterator_next (iterator))
195 {
196 iterator_current (iterator, (void **)&filter_record);
197 if ((filter_record->_is_filter
198 && filter_record->_is_filter (filter_record, name))
199 || (strcasecmp (filter_record->name, name) == 0))
200 {
201 found = 1;
202 if (filter_record->_get_filter)
203 filter_record->_get_filter (filter_record, &f_init);
204 else
205 f_init = filter_record->_filter;
206 break;
207 }
208 }
209 iterator_destroy (&iterator);
210
211 if (found)
212 {
213 int flags = 0;
214 filter_t filter;
215
216 filter = calloc (1, sizeof (*filter));
217 if (filter == NULL)
218 return ENOMEM;
219
220 stream_get_flags (stream, &flags);
221 status = stream_create (pstream, flags | MU_STREAM_NO_CHECK, filter);
222 if (status != 0)
223 {
224 free (filter);
225 return status;
226 }
227
228 filter->stream = stream;
229 filter->filter_stream = *pstream;
230 filter->direction = (direction == 0) ? MU_STREAM_READ : direction;
231 filter->type = type;
232
233 status = property_create (&(filter->property), filter);
234 if (status != 0)
235 {
236 stream_destroy (pstream, filter);
237 free (filter);
238 return status;
239 }
240 property_add_defaults (filter->property, "DIRECTION",
241 ((filter->direction == MU_STREAM_WRITE) ? "WRITE":
242 (filter->direction == MU_STREAM_RDWR) ? "RDWR" :
243 "READ"), filter_property, NULL, filter);
244 property_add_defaults (filter->property, "NAME", filter_record->name,
245 NULL, NULL, filter);
246 stream_set_property (*pstream, filter->property, filter);
247
248 if (f_init != NULL)
249 {
250 status = f_init (filter);
251 if (status != 0)
252 {
253 stream_destroy (pstream, filter);
254 free (filter);
255 return status;
256 }
257 }
258
259 stream_set_open (*pstream, filter_open, filter );
260 stream_set_close (*pstream, filter_close, filter );
261 stream_set_read (*pstream, filter_read, filter);
262 stream_set_readline (*pstream, filter_readline, filter);
263 stream_set_write (*pstream, filter_write, filter);
264 stream_set_fd (*pstream, filter_get_fd, filter );
265 stream_set_truncate (*pstream, filter_truncate, filter );
266 stream_set_size (*pstream, filter_size, filter );
267 stream_set_flush (*pstream, filter_flush, filter );
268 stream_set_destroy (*pstream, filter_destroy, filter);
269 }
270 else
271 status = ENOENT;
272 return status;
273 }