Commit a6938532 a69385328bc98161a8018763b33fc1a783e3e832 by Sergey Poznyakoff

Improve filter framework. Implement a CRLFDOT filter.

* include/mailutils/filter.h (mu_filter_command) <mu_filter_flush> New command.
(mu_filter_result) <mu_filter_again>: New result code.
(MU_FILTER_MAX_AGAIN): New constant.
(mu_crlfdot_filter): New filter.
* include/mailutils/sys/stream.h (_MU_STR_DIRTY, _MU_STR_WRT)
(_MU_STR_ERR, _MU_STR_EOF, _MU_STR_INTERN_MASK): Avoid conflicts with
MU_STREAM_ constants from mailutils/stream.h

* mailbox/crlfdot.c: New source.
* mailbox/Makefile.am (libmailutils_la_SOURCES): Add crlfdot.c.
* mailbox/filter.c (mu_filter_get_list): Register mu_crlfdot_filter.
* mailbox/fltstream.c (init_iobuf): Fix initialization of isize and
input.
(filter_read): Redo the loop, allowing xcode to request a new
iteration by returning mu_filter_again.
(filter_write_internal): Likewise.
(filter_wr_flush): Call filter_write_internal with mu_filter_flush, reserving
mu_filter_lastbuf for really last buffers.
(filter_close): Call filter_write_internal with mu_filter_lastbuf.
* mailbox/stream.c (mu_stream_skip_input_bytes): Clear MU_STREAM_SEEK bit
before actually doing anything.

* include/mailutils/sys/pop3.h [DMALLOC]: Remove unneeded cond.
1 parent 825d8a78
...@@ -50,7 +50,8 @@ enum mu_filter_command ...@@ -50,7 +50,8 @@ enum mu_filter_command
50 mu_filter_init, 50 mu_filter_init,
51 mu_filter_done, 51 mu_filter_done,
52 mu_filter_xcode, 52 mu_filter_xcode,
53 mu_filter_lastbuf 53 mu_filter_lastbuf,
54 mu_filter_flush
54 }; 55 };
55 56
56 enum mu_filter_result 57 enum mu_filter_result
...@@ -58,9 +59,12 @@ enum mu_filter_result ...@@ -58,9 +59,12 @@ enum mu_filter_result
58 mu_filter_ok, 59 mu_filter_ok,
59 mu_filter_falure, 60 mu_filter_falure,
60 mu_filter_moreinput, 61 mu_filter_moreinput,
61 mu_filter_moreoutput 62 mu_filter_moreoutput,
63 mu_filter_again
62 }; 64 };
63 65
66 #define MU_FILTER_MAX_AGAIN 5
67
64 typedef int (*mu_filter_new_data_t) (void **, int, void *); 68 typedef int (*mu_filter_new_data_t) (void **, int, void *);
65 typedef enum mu_filter_result (*mu_filter_xcode_t) (void *data, 69 typedef enum mu_filter_result (*mu_filter_xcode_t) (void *data,
66 enum mu_filter_command cmd, 70 enum mu_filter_command cmd,
...@@ -88,8 +92,9 @@ extern int mu_filter_create (mu_stream_t *, mu_stream_t, const char*, ...@@ -88,8 +92,9 @@ extern int mu_filter_create (mu_stream_t *, mu_stream_t, const char*,
88 extern int mu_filter_get_list (mu_list_t *); 92 extern int mu_filter_get_list (mu_list_t *);
89 93
90 /* List of defaults. */ 94 /* List of defaults. */
91 extern mu_filter_record_t mu_crlf_filter; 95 extern mu_filter_record_t mu_crlf_filter;
92 extern mu_filter_record_t mu_rfc822_filter; 96 extern mu_filter_record_t mu_rfc822_filter;
97 extern mu_filter_record_t mu_crlfdot_filter;
93 extern mu_filter_record_t mu_qp_filter; /* quoted-printable. */ 98 extern mu_filter_record_t mu_qp_filter; /* quoted-printable. */
94 extern mu_filter_record_t mu_base64_filter; 99 extern mu_filter_record_t mu_base64_filter;
95 extern mu_filter_record_t mu_binary_filter; 100 extern mu_filter_record_t mu_binary_filter;
......
...@@ -25,10 +25,6 @@ ...@@ -25,10 +25,6 @@
25 #include <mailutils/errno.h> 25 #include <mailutils/errno.h>
26 #include <mailutils/cstr.h> 26 #include <mailutils/cstr.h>
27 27
28 #ifdef DMALLOC
29 # include <dmalloc.h>
30 #endif
31
32 #ifdef __cplusplus 28 #ifdef __cplusplus
33 extern "C" { 29 extern "C" {
34 #endif 30 #endif
......
...@@ -17,12 +17,12 @@ ...@@ -17,12 +17,12 @@
17 #ifndef _MAILUTILS_SYS_STREAM_H 17 #ifndef _MAILUTILS_SYS_STREAM_H
18 #define _MAILUTILS_SYS_STREAM_H 18 #define _MAILUTILS_SYS_STREAM_H
19 19
20 #define _MU_STR_DIRTY 0x1000 /* Buffer dirty */ 20 #define _MU_STR_DIRTY 0x10000000 /* Buffer dirty */
21 #define _MU_STR_WRT 0x2000 /* Unflushed write pending */ 21 #define _MU_STR_WRT 0x20000000 /* Unflushed write pending */
22 #define _MU_STR_ERR 0x4000 /* Permanent error state */ 22 #define _MU_STR_ERR 0x40000000 /* Permanent error state */
23 #define _MU_STR_EOF 0x8000 /* EOF encountered */ 23 #define _MU_STR_EOF 0x80000000 /* EOF encountered */
24 24
25 #define _MU_STR_INTERN_MASK 0xf000 25 #define _MU_STR_INTERN_MASK 0xf0000000
26 26
27 #define _MU_STR_EVENT_SET 1 27 #define _MU_STR_EVENT_SET 1
28 #define _MU_STR_EVENT_CLR 2 28 #define _MU_STR_EVENT_CLR 2
......
...@@ -63,6 +63,7 @@ libmailutils_la_SOURCES = \ ...@@ -63,6 +63,7 @@ libmailutils_la_SOURCES = \
63 cfg_format.c\ 63 cfg_format.c\
64 cfg_lexer.c\ 64 cfg_lexer.c\
65 cfg_parser.c\ 65 cfg_parser.c\
66 crlfdot.c\
66 crlfflt.c\ 67 crlfflt.c\
67 cstrlower.c\ 68 cstrlower.c\
68 cstrupper.c\ 69 cstrupper.c\
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2003, 2007, 2010 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library 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 GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library; if not, write to the
16 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301 USA */
18
19 /* This source implements a CRLFDOT filter, useful for data I/O in
20 such protocols as POP3 and SMTP. When encoding, this filter
21 replaces each '\n' not following '\r' by "\r\n" and "byte-stuffs"
22 the input by outputting an additional '.' in front of any '.' appearing
23 at the beginning of a line. Upon closing the filter in this mode, it
24 outputs additional ".\r\n".
25
26 When decoding, the reverse is performed: each "\r\n" is replaced by a
27 '\n', and additional '.' are removed from beginning of lines. A single
28 dot on a line by itself marks end of the stream.
29 */
30
31 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34
35 #include <stdlib.h>
36 #include <string.h>
37 #include <mailutils/errno.h>
38 #include <mailutils/filter.h>
39 #include <mailutils/stream.h>
40
41 enum crlfdot_decode_state
42 {
43 crlfdot_decode_init, /* initial state */
44 crlfdot_decode_char, /* Any character excepting [\r\n.] */
45 crlfdot_decode_cr, /* prev. char was \r */
46 crlfdot_decode_crlf, /* 2 prev. char were \r\n */
47 crlfdot_decode_dot, /* 3 prev. chars were \r\n. */
48 crlfdot_decode_dotcr, /* 4 prev. chars were \r\n.\r */
49 crlfdot_decode_end /* final state, a \r\n.\r\n seen. */
50 };
51
52 static enum crlfdot_decode_state
53 new_decode_state (enum crlfdot_decode_state state, int c)
54 {
55 switch (state)
56 {
57 case crlfdot_decode_init:
58 switch (c)
59 {
60 case '\r':
61 return crlfdot_decode_cr;
62 case '.':
63 return crlfdot_decode_dot;
64 }
65 break;
66
67 case crlfdot_decode_char:
68 switch (c)
69 {
70 case '\r':
71 return crlfdot_decode_cr;
72 }
73 break;
74
75 case crlfdot_decode_cr:
76 switch (c)
77 {
78 case '\r':
79 return crlfdot_decode_cr;
80 case '\n':
81 return crlfdot_decode_crlf;
82 }
83 break;
84
85 case crlfdot_decode_crlf:
86 switch (c)
87 {
88 case '\r':
89 return crlfdot_decode_cr;
90 case '.':
91 return crlfdot_decode_dot;
92 }
93
94 case crlfdot_decode_dot:
95 switch (c)
96 {
97 case '\r':
98 return crlfdot_decode_dotcr;
99 }
100 break;
101
102 case crlfdot_decode_dotcr:
103 switch (c)
104 {
105 case '\n':
106 return crlfdot_decode_end;
107 }
108
109 case crlfdot_decode_end:
110 break;
111 }
112 return crlfdot_decode_char;
113 }
114
115 /* Move min(isize,osize) bytes from iptr to optr, replacing each \r\n
116 with \n. */
117 static enum mu_filter_result
118 _crlfdot_decoder (void *xd,
119 enum mu_filter_command cmd,
120 struct mu_filter_io *iobuf)
121 {
122 int *pstate = xd;
123 size_t i, j;
124 const unsigned char *iptr;
125 size_t isize;
126 char *optr;
127 size_t osize;
128
129 switch (cmd)
130 {
131 case mu_filter_init:
132 *pstate = crlfdot_decode_init;
133 return mu_filter_ok;
134
135 case mu_filter_done:
136 return mu_filter_ok;
137
138 default:
139 break;
140 }
141
142 iptr = (const unsigned char *) iobuf->input;
143 isize = iobuf->isize;
144 optr = iobuf->output;
145 osize = iobuf->osize;
146
147 for (i = j = 0; *pstate != crlfdot_decode_end && i < isize && j < osize; i++)
148 {
149 unsigned char c = *iptr++;
150
151 if (c == '\r')
152 {
153 if (i + 1 == isize)
154 break;
155 *pstate = new_decode_state (*pstate, c);
156 if (*iptr == '\n')
157 continue;
158 }
159 else if (c == '.' &&
160 (*pstate == crlfdot_decode_init ||
161 *pstate == crlfdot_decode_crlf))
162 {
163 /* Make sure we have two more characters in the buffer */
164 if (i + 2 == isize)
165 break;
166 *pstate = new_decode_state (*pstate, c);
167 if (*iptr != '\r')
168 continue;
169 }
170 else
171 *pstate = new_decode_state (*pstate, c);
172 optr[j++] = c;
173 }
174
175 if (*pstate == crlfdot_decode_end)
176 {
177 j -= 2; /* remove the trailing .\n */
178 iobuf->eof = 1;
179 }
180 iobuf->isize = i;
181 iobuf->osize = j;
182 return mu_filter_ok;
183 }
184
185 enum crlfdot_encode_state
186 {
187 crlfdot_encode_init, /* initial state */
188 crlfdot_encode_char, /* Any character excepting [\r\n] */
189 crlfdot_encode_cr, /* prev. char was \r */
190 crlfdot_encode_lf, /* prev. char was \n */
191 };
192
193 static enum crlfdot_encode_state
194 new_encode_state (enum crlfdot_encode_state state, int c)
195 {
196 switch (c)
197 {
198 case '\r':
199 return crlfdot_encode_cr;
200
201 case '\n':
202 return crlfdot_encode_lf;
203 }
204 return crlfdot_encode_char;
205 }
206
207 /* Move min(isize,osize) bytes from iptr to optr, replacing each \n
208 with \r\n. Any input \r\n sequences remain untouched. */
209 static enum mu_filter_result
210 _crlfdot_encoder (void *xd,
211 enum mu_filter_command cmd,
212 struct mu_filter_io *iobuf)
213 {
214 enum mu_filter_result result;
215 size_t i, j;
216 const unsigned char *iptr;
217 size_t isize;
218 char *optr;
219 size_t osize;
220 int *state = xd;
221
222 iptr = (const unsigned char *) iobuf->input;
223 isize = iobuf->isize;
224 optr = iobuf->output;
225 osize = iobuf->osize;
226
227 switch (cmd)
228 {
229 case mu_filter_init:
230 *state = crlfdot_encode_init;
231 return mu_filter_ok;
232
233 case mu_filter_done:
234 return mu_filter_ok;
235
236 default:
237 break;
238 }
239
240 for (i = j = 0; i < isize && j < osize; i++, iptr++)
241 {
242 unsigned char c = *iptr;
243 int curstate = *state;
244
245 if (c == '\n')
246 {
247 if (curstate == crlfdot_encode_cr)
248 optr[j++] = c;
249 else if (j + 1 == osize)
250 {
251 if (i == 0)
252 {
253 iobuf->osize = 2;
254 return mu_filter_moreoutput;
255 }
256 break;
257 }
258 else
259 {
260 optr[j++] = '\r';
261 optr[j++] = '\n';
262 }
263 }
264 else if (c == '.' &&
265 (curstate == crlfdot_encode_init ||
266 curstate == crlfdot_encode_lf))
267 {
268 if (j + 2 > osize)
269 {
270 if (i == 0)
271 {
272 iobuf->osize = 2;
273 return mu_filter_moreoutput;
274 }
275 break;
276 }
277 optr[j++] = '.';
278 optr[j++] = '.';
279 }
280 else
281 optr[j++] = c;
282
283 *state = new_encode_state (curstate, c);
284 }
285
286 result = mu_filter_ok;
287 if (cmd == mu_filter_lastbuf)
288 {
289 switch (*state)
290 {
291 case crlfdot_encode_lf:
292 if (j + 3 > osize)
293 result = mu_filter_again;
294 break;
295
296 default:
297 if (j + 5 > osize)
298 result = mu_filter_again;
299 else
300 {
301 optr[j++] = '\r';
302 optr[j++] = '\n';
303 }
304 }
305
306 if (result == mu_filter_ok)
307 {
308 optr[j++] = '.';
309 optr[j++] = '\r';
310 optr[j++] = '\n';
311 }
312 }
313
314 iobuf->isize = i;
315 iobuf->osize = j;
316 return result;
317 }
318
319 static int
320 alloc_state (void **pret, int mode MU_ARG_UNUSED, void *data MU_ARG_UNUSED)
321 {
322 *pret = malloc (sizeof (int));
323 if (!*pret)
324 return ENOMEM;
325 return 0;
326 }
327
328 static struct _mu_filter_record _crlfdot_filter = {
329 "CRLFDOT",
330 0,
331 alloc_state,
332 _crlfdot_encoder,
333 _crlfdot_decoder
334 };
335
336 mu_filter_record_t mu_crlfdot_filter = &_crlfdot_filter;
...@@ -74,6 +74,7 @@ mu_filter_get_list (mu_list_t *plist) ...@@ -74,6 +74,7 @@ mu_filter_get_list (mu_list_t *plist)
74 mu_list_append (filter_list, mu_bit7_filter); 74 mu_list_append (filter_list, mu_bit7_filter);
75 mu_list_append (filter_list, mu_rfc822_filter); 75 mu_list_append (filter_list, mu_rfc822_filter);
76 mu_list_append (filter_list, mu_crlf_filter); 76 mu_list_append (filter_list, mu_crlf_filter);
77 mu_list_append (filter_list, mu_crlfdot_filter);
77 mu_list_append (filter_list, mu_rfc_2047_Q_filter); 78 mu_list_append (filter_list, mu_rfc_2047_Q_filter);
78 mu_list_append (filter_list, mu_rfc_2047_B_filter); 79 mu_list_append (filter_list, mu_rfc_2047_B_filter);
79 /* FIXME: add the default encodings? */ 80 /* FIXME: add the default encodings? */
......
...@@ -45,8 +45,8 @@ ...@@ -45,8 +45,8 @@
45 static void 45 static void
46 init_iobuf (struct mu_filter_io *io, struct _mu_filter_stream *fs) 46 init_iobuf (struct mu_filter_io *io, struct _mu_filter_stream *fs)
47 { 47 {
48 io->input = MFB_BASE (fs->inbuf); 48 io->input = MFB_CURPTR (fs->inbuf);
49 io->isize = MFB_LEVEL (fs->inbuf); 49 io->isize = MFB_RDBYTES (fs->inbuf);
50 io->output = MFB_ENDPTR (fs->outbuf); 50 io->output = MFB_ENDPTR (fs->outbuf);
51 io->osize = MFB_FREESIZE (fs->outbuf); 51 io->osize = MFB_FREESIZE (fs->outbuf);
52 io->errcode = 0; 52 io->errcode = 0;
...@@ -111,14 +111,15 @@ static int ...@@ -111,14 +111,15 @@ static int
111 filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) 111 filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret)
112 { 112 {
113 struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream; 113 struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream;
114 enum mu_filter_command cmd = mu_filter_xcode;
115 struct mu_filter_io iobuf; 114 struct mu_filter_io iobuf;
116 size_t min_input_level = MU_FILTER_BUF_SIZE; 115 size_t min_input_level = MU_FILTER_BUF_SIZE;
117 size_t min_output_size = MU_FILTER_BUF_SIZE; 116 size_t min_output_size = MU_FILTER_BUF_SIZE;
117 enum mu_filter_command cmd = mu_filter_xcode;
118 size_t total = 0; 118 size_t total = 0;
119 int stop = 0; 119 int stop = 0;
120 int again = 0;
120 121
121 while (!stop && total < size && cmd != mu_filter_lastbuf) 122 do
122 { 123 {
123 size_t rdsize; 124 size_t rdsize;
124 125
...@@ -127,7 +128,7 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) ...@@ -127,7 +128,7 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret)
127 enum mu_filter_result res; 128 enum mu_filter_result res;
128 int rc; 129 int rc;
129 130
130 if (MFB_RDBYTES (fs->inbuf) < min_input_level) 131 if (MFB_RDBYTES (fs->inbuf) < min_input_level && !again)
131 { 132 {
132 rc = MFB_require (&fs->inbuf, min_input_level); 133 rc = MFB_require (&fs->inbuf, min_input_level);
133 if (rc) 134 if (rc)
...@@ -139,9 +140,10 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) ...@@ -139,9 +140,10 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret)
139 if (rc) 140 if (rc)
140 return rc; 141 return rc;
141 if (rdsize == 0 && 142 if (rdsize == 0 &&
142 MFB_RDBYTES (fs->outbuf) == 0 143 MFB_RDBYTES (fs->outbuf) == 0 &&
143 && MFB_RDBYTES (fs->inbuf) == 0) 144 MFB_RDBYTES (fs->inbuf) == 0)
144 break; 145 cmd = mu_filter_lastbuf;
146
145 MFB_advance_level (&fs->inbuf, rdsize); 147 MFB_advance_level (&fs->inbuf, rdsize);
146 } 148 }
147 149
...@@ -153,16 +155,24 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) ...@@ -153,16 +155,24 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret)
153 155
154 init_iobuf (&iobuf, fs); 156 init_iobuf (&iobuf, fs);
155 157
156 cmd = mu_stream_eof (fs->transport) ? 158 if (cmd != mu_filter_lastbuf)
157 mu_filter_lastbuf : mu_filter_xcode; 159 cmd = mu_stream_eof (fs->transport) ?
160 mu_filter_lastbuf : mu_filter_xcode;
158 res = fs->xcode (fs->xdata, cmd, &iobuf); 161 res = fs->xcode (fs->xdata, cmd, &iobuf);
159 switch (res) 162 switch (res)
160 { 163 {
164 case mu_filter_again:
165 if (++again > MU_FILTER_MAX_AGAIN)
166 {
167 /* FIXME: What filter? Need some id. */
168 mu_error (_("filter returned `again' too many times"));
169 again = 0;
170 }
171 break;
172
161 case mu_filter_ok: 173 case mu_filter_ok:
162 if (iobuf.isize > MFB_RDBYTES (fs->inbuf) 174 again = 0;
163 || iobuf.osize > MFB_FREESIZE (fs->outbuf)) 175 if (cmd == mu_filter_lastbuf || iobuf.eof)
164 return MU_ERR_FAILURE; /* FIXME: special error code? */
165 if (iobuf.eof)
166 { 176 {
167 _mu_stream_seteof (stream); 177 _mu_stream_seteof (stream);
168 stop = 1; 178 stop = 1;
...@@ -181,6 +191,10 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) ...@@ -181,6 +191,10 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret)
181 continue; 191 continue;
182 } 192 }
183 193
194 if (iobuf.isize > MFB_RDBYTES (fs->inbuf)
195 || iobuf.osize > MFB_FREESIZE (fs->outbuf))
196 return MU_ERR_FAILURE; /* FIXME: special error code? */
197
184 /* iobuf.osize contains number of bytes written to output */ 198 /* iobuf.osize contains number of bytes written to output */
185 MFB_advance_level (&fs->outbuf, iobuf.osize); 199 MFB_advance_level (&fs->outbuf, iobuf.osize);
186 200
...@@ -194,8 +208,10 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret) ...@@ -194,8 +208,10 @@ filter_read (mu_stream_t stream, char *buf, size_t size, size_t *pret)
194 memcpy (buf + total, MFB_CURPTR (fs->outbuf), rdsize); 208 memcpy (buf + total, MFB_CURPTR (fs->outbuf), rdsize);
195 MFB_advance_pos (&fs->outbuf, rdsize); 209 MFB_advance_pos (&fs->outbuf, rdsize);
196 total += rdsize; 210 total += rdsize;
197 }
198 211
212 }
213 while (!stop && (total < size || again));
214
199 *pret = total; 215 *pret = total;
200 return 0; 216 return 0;
201 } 217 }
...@@ -217,6 +233,8 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd, ...@@ -217,6 +233,8 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd,
217 size_t min_output_size = MU_FILTER_BUF_SIZE; 233 size_t min_output_size = MU_FILTER_BUF_SIZE;
218 size_t total = 0; 234 size_t total = 0;
219 int rc = 0; 235 int rc = 0;
236 int again;
237 int stop = 0;
220 238
221 do 239 do
222 { 240 {
...@@ -249,19 +267,22 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd, ...@@ -249,19 +267,22 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd,
249 res = fs->xcode (fs->xdata, cmd, &iobuf); 267 res = fs->xcode (fs->xdata, cmd, &iobuf);
250 switch (res) 268 switch (res)
251 { 269 {
270 case mu_filter_again:
271 if (++again > MU_FILTER_MAX_AGAIN)
272 {
273 /* FIXME: What filter? Need some id. */
274 mu_error (_("filter returned `again' too many times"));
275 again = 0;
276 }
277 break;
278
252 case mu_filter_ok: 279 case mu_filter_ok:
253 if (iobuf.isize == 0 || iobuf.osize == 0) 280 again = 0;
281 if (cmd == mu_filter_lastbuf || iobuf.eof)
254 { 282 {
255 /* FIXME: Hack to handle eventual buggy filters */ 283 _mu_stream_seteof (stream);
256 if (iobuf.isize == 0) 284 stop = 1;
257 min_input_level++;
258 if (iobuf.osize == 0)
259 min_output_size++;
260 continue;
261 } 285 }
262 if (iobuf.isize > MFB_RDBYTES (fs->inbuf)
263 || iobuf.osize > MFB_FREESIZE (fs->outbuf))
264 return MU_ERR_FAILURE; /* FIXME: special error code? */
265 break; 286 break;
266 287
267 case mu_filter_falure: 288 case mu_filter_falure:
...@@ -276,24 +297,26 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd, ...@@ -276,24 +297,26 @@ filter_write_internal (mu_stream_t stream, enum mu_filter_command cmd,
276 continue; 297 continue;
277 } 298 }
278 299
300 if (iobuf.isize > MFB_RDBYTES (fs->inbuf)
301 || iobuf.osize > MFB_FREESIZE (fs->outbuf))
302 return MU_ERR_FAILURE; /* FIXME: special error code? */
303
279 /* iobuf.osize contains number of bytes written to output */ 304 /* iobuf.osize contains number of bytes written to output */
280 MFB_advance_level (&fs->outbuf, iobuf.osize); 305 MFB_advance_level (&fs->outbuf, iobuf.osize);
281 306
282 /* iobuf.isize contains number of bytes read from input */ 307 /* iobuf.isize contains number of bytes read from input */
283 MFB_advance_pos (&fs->inbuf, iobuf.isize); 308 MFB_advance_pos (&fs->inbuf, iobuf.isize);
284 309
285 rdsize = size - total;
286 if (rdsize > MFB_RDBYTES (fs->outbuf))
287 rdsize = MFB_RDBYTES (fs->outbuf);
288
289 rc = mu_stream_write (fs->transport, 310 rc = mu_stream_write (fs->transport,
290 MFB_CURPTR (fs->outbuf), MFB_RDBYTES (fs->outbuf), 311 MFB_CURPTR (fs->outbuf),
312 MFB_RDBYTES (fs->outbuf),
291 &rdsize); 313 &rdsize);
292 MFB_advance_pos (&fs->outbuf, rdsize); 314 if (rc == 0)
293 if (rc) 315 MFB_advance_pos (&fs->outbuf, rdsize);
316 else
294 break; 317 break;
295 } 318 }
296 while (MFB_RDBYTES (fs->outbuf)); 319 while (!stop && (MFB_RDBYTES (fs->outbuf) || again));
297 if (pret) 320 if (pret)
298 *pret = total; 321 *pret = total;
299 else if (total < size && rc == 0) 322 else if (total < size && rc == 0)
...@@ -311,7 +334,8 @@ static int ...@@ -311,7 +334,8 @@ static int
311 filter_wr_flush (mu_stream_t stream) 334 filter_wr_flush (mu_stream_t stream)
312 { 335 {
313 struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream; 336 struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream;
314 int rc = filter_write_internal (stream, mu_filter_lastbuf, NULL, 0, NULL); 337 size_t dummy;
338 int rc = filter_write_internal (stream, mu_filter_flush, NULL, 0, &dummy);
315 if (rc == 0) 339 if (rc == 0)
316 rc = mu_stream_flush (fs->transport); 340 rc = mu_stream_flush (fs->transport);
317 return rc; 341 return rc;
...@@ -380,6 +404,8 @@ static int ...@@ -380,6 +404,8 @@ static int
380 filter_close (mu_stream_t stream) 404 filter_close (mu_stream_t stream)
381 { 405 {
382 struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream; 406 struct _mu_filter_stream *fs = (struct _mu_filter_stream *)stream;
407 size_t dummy;
408 int rc = filter_write_internal (stream, mu_filter_lastbuf, NULL, 0, &dummy);
383 MBF_CLEAR (fs->inbuf); 409 MBF_CLEAR (fs->inbuf);
384 MBF_CLEAR (fs->outbuf); 410 MBF_CLEAR (fs->outbuf);
385 return mu_stream_close (fs->transport); 411 return mu_stream_close (fs->transport);
......
...@@ -380,10 +380,10 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence, ...@@ -380,10 +380,10 @@ mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence,
380 input operations. 380 input operations.
381 381
382 This function is designed to help implement seek method in otherwise 382 This function is designed to help implement seek method in otherwise
383 unseekable streams (such as filters). Do not use it if you absolutely 383 unseekable streams (such as filters). Do not use it unless you absolutely
384 have to. Using it on an unbuffered stream is a terrible waste of CPU. */ 384 have to. Using it on an unbuffered stream is a terrible waste of CPU. */
385 int 385 static int
386 mu_stream_skip_input_bytes (mu_stream_t stream, mu_off_t count, mu_off_t *pres) 386 _stream_skip_input_bytes (mu_stream_t stream, mu_off_t count, mu_off_t *pres)
387 { 387 {
388 mu_off_t pos; 388 mu_off_t pos;
389 int rc; 389 int rc;
...@@ -439,6 +439,22 @@ mu_stream_skip_input_bytes (mu_stream_t stream, mu_off_t count, mu_off_t *pres) ...@@ -439,6 +439,22 @@ mu_stream_skip_input_bytes (mu_stream_t stream, mu_off_t count, mu_off_t *pres)
439 return rc; 439 return rc;
440 } 440 }
441 441
442 /* A wrapper for the above function. It is normally called from a
443 seek method implementation, so it makes sure the MU_STREAM_SEEK
444 is cleared while in _stream_skip_input_bytes, to avoid infitite
445 recursion that may be triggered by _stream_flush_buffer invoking
446 stream->seek. */
447 int
448 mu_stream_skip_input_bytes (mu_stream_t stream, mu_off_t count, mu_off_t *pres)
449 {
450 int rc;
451 int seek_flag = stream->flags & MU_STREAM_SEEK;
452 stream->flags &= ~MU_STREAM_SEEK;
453 rc = _stream_skip_input_bytes (stream, count, pres);
454 stream->flags |= seek_flag;
455 return rc;
456 }
457
442 int 458 int
443 mu_stream_set_buffer (mu_stream_t stream, enum mu_buffer_type type, 459 mu_stream_set_buffer (mu_stream_t stream, enum mu_buffer_type type,
444 size_t size) 460 size_t size)
......