Commit dd8d091b dd8d091ba3cae58fd437c664478de8bcbdf25ac6 by Sergey Poznyakoff

Implement a filter for quoting ^From. Use it for appending to UNIX mailboxes.

* libmailutils/fromflt.c: New file.
* libmailutils/Makefile.am (libmailutils_la_SOURCES): Add fromflt.c
* libmailutils/tests/testsuite.at: Include fromflt.at.
* include/mailutils/filter.h (mu_from_filter): New filter type.
* libmailutils/filter.c (mu_filter_get_list): Register mu_from_filter.

* libmailutils/fromflt.at: New file.
* libmailutils/tests/Makefile.am (TESTSUITE_AT): Add fromflt.at.
* libmailutils/tests/base64d.at: Mention `filter' in the keywords.
* libmailutils/tests/base64e.at: Likewise.
* libmailutils/tests/fltst.c (main): Fix argc check.

* libproto/mbox/mbox.c (append_message_to_stream): Use "FROM" filter.
1 parent f24df125
...@@ -103,7 +103,8 @@ extern mu_filter_record_t mu_bit8_filter; ...@@ -103,7 +103,8 @@ extern mu_filter_record_t mu_bit8_filter;
103 extern mu_filter_record_t mu_bit7_filter; 103 extern mu_filter_record_t mu_bit7_filter;
104 extern mu_filter_record_t mu_rfc_2047_Q_filter; 104 extern mu_filter_record_t mu_rfc_2047_Q_filter;
105 extern mu_filter_record_t mu_rfc_2047_B_filter; 105 extern mu_filter_record_t mu_rfc_2047_B_filter;
106 106 extern mu_filter_record_t mu_from_filter;
107
107 enum mu_iconv_fallback_mode 108 enum mu_iconv_fallback_mode
108 { 109 {
109 mu_fallback_none, 110 mu_fallback_none,
......
...@@ -83,6 +83,7 @@ libmailutils_la_SOURCES = \ ...@@ -83,6 +83,7 @@ libmailutils_la_SOURCES = \
83 fltstream.c\ 83 fltstream.c\
84 folder.c\ 84 folder.c\
85 freeitem.c\ 85 freeitem.c\
86 fromflt.c\
86 gdebug.c\ 87 gdebug.c\
87 getpass.c\ 88 getpass.c\
88 gocs.c\ 89 gocs.c\
......
...@@ -78,6 +78,7 @@ mu_filter_get_list (mu_list_t *plist) ...@@ -78,6 +78,7 @@ mu_filter_get_list (mu_list_t *plist)
78 mu_list_append (filter_list, mu_dot_filter); 78 mu_list_append (filter_list, mu_dot_filter);
79 mu_list_append (filter_list, mu_rfc_2047_Q_filter); 79 mu_list_append (filter_list, mu_rfc_2047_Q_filter);
80 mu_list_append (filter_list, mu_rfc_2047_B_filter); 80 mu_list_append (filter_list, mu_rfc_2047_B_filter);
81 mu_list_append (filter_list, mu_from_filter);
81 /* FIXME: add the default encodings? */ 82 /* FIXME: add the default encodings? */
82 } 83 }
83 *plist = filter_list; 84 *plist = filter_list;
......
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 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <mailutils/errno.h>
26 #include <mailutils/filter.h>
27 #include <mailutils/stream.h>
28
29 enum from_decode_state
30 {
31 from_decode_init,
32 from_decode_nl,
33 from_decode_char
34 };
35
36 #define GT_FROM_MARK_STR ">From "
37 #define GT_FROM_MARK_LEN (sizeof (GT_FROM_MARK_STR) - 1)
38
39 /* Move min(isize,osize) bytes from iptr to optr, replacing each '>From '
40 at the beginning of line with 'From '. */
41 static enum mu_filter_result
42 _from_decoder (void *xd,
43 enum mu_filter_command cmd,
44 struct mu_filter_io *iobuf)
45 {
46 int *pstate = xd;
47 const unsigned char *iptr;
48 size_t isize;
49 char *optr;
50 size_t osize;
51 enum from_decode_state state;
52 size_t i, j;
53
54 switch (cmd)
55 {
56 case mu_filter_init:
57 *pstate = from_decode_init;
58 return mu_filter_ok;
59
60 case mu_filter_done:
61 return mu_filter_ok;
62
63 default:
64 state = *pstate;
65 break;
66 }
67
68 iptr = (const unsigned char *) iobuf->input;
69 isize = iobuf->isize;
70 optr = iobuf->output;
71 osize = iobuf->osize;
72
73 for (i = j = 0; i < isize && j < osize; i++)
74 {
75 unsigned char c = *iptr++;
76
77 if (c == '\n')
78 state = from_decode_nl;
79 else if (state == from_decode_init || state == from_decode_nl)
80 {
81 size_t len = isize - i;
82
83 if (len < GT_FROM_MARK_LEN)
84 {
85 if (memcmp (iptr - 1, GT_FROM_MARK_STR, len) == 0)
86 {
87 if (i == 0)
88 {
89 iobuf->isize = GT_FROM_MARK_LEN - len;
90 return mu_filter_moreinput;
91 }
92 break;
93 }
94 else
95 state = from_decode_char;
96 }
97 else if (memcmp (iptr - 1, GT_FROM_MARK_STR, GT_FROM_MARK_LEN) == 0)
98 {
99 /* Skip > */
100 state = from_decode_char;
101 continue;
102 }
103 }
104 optr[j++] = c;
105 }
106
107 *pstate = state;
108 iobuf->isize = i;
109 iobuf->osize = j;
110 return mu_filter_ok;
111 }
112
113 #define FROM_MARK_STR "From "
114 #define FROM_MARK_LEN (sizeof (FROM_MARK_STR) - 1)
115
116 enum from_encode_state
117 {
118 from_encode_init,
119 from_encode_nl,
120 from_encode_char,
121 from_encode_gt,
122 from_encode_f,
123 from_encode_r,
124 from_encode_o,
125 from_encode_m,
126 from_encode_sp
127 };
128
129 static int length_to_state_tab[] = {
130 from_encode_gt,
131 from_encode_f,
132 from_encode_r,
133 from_encode_o,
134 from_encode_m,
135 from_encode_sp
136 };
137
138 static int state_to_length_tab[] = {
139 0, 0, 0,
140 GT_FROM_MARK_LEN,
141 GT_FROM_MARK_LEN-1,
142 GT_FROM_MARK_LEN-2,
143 GT_FROM_MARK_LEN-3,
144 GT_FROM_MARK_LEN-4,
145 GT_FROM_MARK_LEN-5
146 };
147
148 /* Move min(isize,osize) bytes from iptr to optr, replacing each 'From '
149 at the beginning of line with '>From '. */
150
151 static enum mu_filter_result
152 _from_encoder (void *xd,
153 enum mu_filter_command cmd,
154 struct mu_filter_io *iobuf)
155 {
156 int *pstate = xd;
157 const unsigned char *iptr;
158 size_t isize;
159 char *optr;
160 size_t osize;
161 enum from_encode_state state;
162 size_t i, j;
163
164 switch (cmd)
165 {
166 case mu_filter_init:
167 *pstate = from_encode_init;
168 return mu_filter_ok;
169
170 case mu_filter_done:
171 return mu_filter_ok;
172
173 default:
174 state = *pstate;
175 switch (state)
176 {
177 case from_encode_init:
178 case from_encode_nl:
179 case from_encode_char:
180 break;
181
182 default:
183 osize = state_to_length_tab[state];
184 if (iobuf->osize < osize)
185 {
186 iobuf->osize = osize;
187 return mu_filter_moreoutput;
188 }
189 memcpy (iobuf->output, GT_FROM_MARK_STR + GT_FROM_MARK_LEN - osize,
190 osize);
191 iobuf->osize = osize;
192 iobuf->isize = osize;
193 *pstate = from_encode_init;
194 return mu_filter_ok;
195 }
196 break;
197 }
198
199 iptr = (const unsigned char *) iobuf->input;
200 isize = iobuf->isize;
201 optr = iobuf->output;
202 osize = iobuf->osize;
203
204 for (i = j = 0; i < isize && j < osize; i++)
205 {
206 unsigned char c = *iptr++;
207
208 if (c == '\n')
209 state = from_encode_nl;
210 else if (state == from_encode_init || state == from_encode_nl)
211 {
212 size_t len = isize - i;
213
214 if (len < FROM_MARK_LEN)
215 {
216 if (memcmp (iptr - 1, FROM_MARK_STR, len) == 0)
217 {
218 if (i == 0)
219 {
220 iobuf->isize = FROM_MARK_LEN;
221 return mu_filter_moreinput;
222 }
223 break;
224 }
225 else
226 state = from_encode_char;
227 }
228 else if (memcmp (iptr - 1, FROM_MARK_STR, FROM_MARK_LEN) == 0)
229 {
230 size_t rest = osize - j;
231
232 if (rest > GT_FROM_MARK_LEN)
233 rest = GT_FROM_MARK_LEN;
234 else if (rest < 2)
235 {
236 if (i == 0)
237 {
238 iobuf->osize = GT_FROM_MARK_LEN;
239 return mu_filter_moreoutput;
240 }
241 break;
242 }
243
244 memcpy (optr + j, GT_FROM_MARK_STR, rest);
245 i += rest - 2;
246 iptr += rest - 2;
247 j += rest;
248 if (rest < GT_FROM_MARK_LEN)
249 state = length_to_state_tab[rest];
250 else
251 state = from_encode_char;
252 continue;
253 }
254 else
255 state = from_encode_char;
256 }
257 optr[j++] = c;
258 }
259 *pstate = state;
260 iobuf->isize = i;
261 iobuf->osize = j;
262 return mu_filter_ok;
263 }
264
265 static int
266 _from_alloc_state (void **pret, int mode, void *data MU_ARG_UNUSED)
267 {
268 *pret = malloc (sizeof (int));
269 if (!*pret)
270 return ENOMEM;
271 return 0;
272 }
273
274 static struct _mu_filter_record _from_filter = {
275 "FROM",
276 0,
277 _from_alloc_state,
278 _from_encoder,
279 _from_decoder
280 };
281
282 mu_filter_record_t mu_from_filter = &_from_filter;
283
...@@ -64,6 +64,7 @@ TESTSUITE_AT = \ ...@@ -64,6 +64,7 @@ TESTSUITE_AT = \
64 base64e.at\ 64 base64e.at\
65 decode2047.at\ 65 decode2047.at\
66 encode2047.at\ 66 encode2047.at\
67 fromflt.at\
67 list.at\ 68 list.at\
68 mailcap.at\ 69 mailcap.at\
69 testsuite.at\ 70 testsuite.at\
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
16 # This file is part of Mailfromd testsuite. 16 # This file is part of Mailfromd testsuite.
17 17
18 AT_SETUP([base64 decoding (read)]) 18 AT_SETUP([base64 decoding (read)])
19 AT_KEYWORDS([base64 base64d base64dr decode]) 19 AT_KEYWORDS([base64 base64d base64dr decode filter])
20 20
21 AT_CHECK([ 21 AT_CHECK([
22 cp $abs_top_srcdir/libmailutils/tests/Encode expout 22 cp $abs_top_srcdir/libmailutils/tests/Encode expout
...@@ -28,7 +28,7 @@ AT_CLEANUP ...@@ -28,7 +28,7 @@ AT_CLEANUP
28 28
29 29
30 AT_SETUP([base64 decoding (write)]) 30 AT_SETUP([base64 decoding (write)])
31 AT_KEYWORDS([base64 base64d base64dw decode]) 31 AT_KEYWORDS([base64 base64d base64dw decode filter])
32 32
33 AT_CHECK([ 33 AT_CHECK([
34 cp $abs_top_srcdir/libmailutils/tests/Encode expout 34 cp $abs_top_srcdir/libmailutils/tests/Encode expout
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
16 # This file is part of Mailfromd testsuite. 16 # This file is part of Mailfromd testsuite.
17 17
18 AT_SETUP([base64 encoding (read)]) 18 AT_SETUP([base64 encoding (read)])
19 AT_KEYWORDS([base64 base64e base64er encode]) 19 AT_KEYWORDS([base64 base64e base64er encode filter])
20 20
21 AT_CHECK([ 21 AT_CHECK([
22 cp $abs_top_srcdir/libmailutils/tests/Decode expout 22 cp $abs_top_srcdir/libmailutils/tests/Decode expout
...@@ -28,7 +28,7 @@ AT_CLEANUP ...@@ -28,7 +28,7 @@ AT_CLEANUP
28 28
29 29
30 AT_SETUP([base64 encoding (write)]) 30 AT_SETUP([base64 encoding (write)])
31 AT_KEYWORDS([base64 base64e base64ew encode]) 31 AT_KEYWORDS([base64 base64e base64ew encode filter])
32 32
33 AT_CHECK([ 33 AT_CHECK([
34 cp $abs_top_srcdir/libmailutils/tests/Decode expout 34 cp $abs_top_srcdir/libmailutils/tests/Decode expout
......
...@@ -114,7 +114,7 @@ main (int argc, char * argv []) ...@@ -114,7 +114,7 @@ main (int argc, char * argv [])
114 114
115 if (argc == 1) 115 if (argc == 1)
116 usage (NULL); 116 usage (NULL);
117 if (argc < 3) 117 if (argc < 4)
118 usage ("not enough arguments"); 118 usage ("not enough arguments");
119 119
120 fltname = argv[1]; 120 fltname = argv[1];
......
1 # This file is part of GNU Mailutils. -*- Autotest -*-
2 # Copyright (C) 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
3 #
4 # GNU Mailutils is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 3, or (at
7 # your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
16 # This file is part of Mailfromd testsuite.
17
18 # -------------------------------------------
19 # Data for 'From' filter tests.
20 # -------------------------------------------
21
22 m4_define([from_plain_text],[From this time on
23 from that source
24 From stdin
25 and
26 From them
27 ])
28
29 m4_define([from_encoded_text],[>From this time on
30 from that source
31 From stdin
32 and
33 >From them
34 ])
35
36 # -------------------------------------------
37 # Test 'From' encoding
38 # -------------------------------------------
39
40 # Test read mode
41
42 AT_SETUP([from filter encoding (read)])
43 AT_KEYWORDS([from frome fromer encode])
44
45 AT_CHECK([
46 AT_DATA([input],from_plain_text)
47 fltst from encode read < input
48 ],
49 [0],
50 [from_encoded_text])
51
52 AT_CLEANUP
53
54 # The same, in write mode
55
56 AT_SETUP([from filter encoding (write)])
57 AT_KEYWORDS([from frome fromew encode])
58
59 AT_CHECK([
60 AT_DATA([input],from_plain_text)
61 fltst from encode write < input
62 ],
63 [0],
64 [from_encoded_text])
65
66 AT_CLEANUP
67
68 # -------------------------------------------
69 # Test '>From' decoding
70 # -------------------------------------------
71
72 AT_SETUP([from filter decoding (read)])
73 AT_KEYWORDS([from fromd fromdr decode])
74
75 AT_CHECK([
76 AT_DATA([input],from_encoded_text)
77 fltst from decode read < input
78 ],
79 [0],
80 [from_plain_text])
81
82 AT_CLEANUP
83
84 # The same, in write mode
85
86 AT_SETUP([from filter decoding (write)])
87 AT_KEYWORDS([from fromd fromdw decode])
88
89 AT_CHECK([
90 AT_DATA([input],from_encoded_text)
91 fltst from decode write < input
92 ],
93 [0],
94 [from_plain_text])
95
96 AT_CLEANUP
...@@ -63,4 +63,5 @@ m4_include([base64e.at]) ...@@ -63,4 +63,5 @@ m4_include([base64e.at])
63 m4_include([base64d.at]) 63 m4_include([base64d.at])
64 m4_include([decode2047.at]) 64 m4_include([decode2047.at])
65 m4_include([encode2047.at]) 65 m4_include([encode2047.at])
66 m4_include([fromflt.at])
66 67
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
28 #include <mbox0.h> 28 #include <mbox0.h>
29 #include <mailutils/cstr.h> 29 #include <mailutils/cstr.h>
30 #include <mailutils/io.h> 30 #include <mailutils/io.h>
31 #include <mailutils/filter.h>
31 32
32 #define ATTRIBUTE_IS_DELETED(flag) (flag & MU_ATTRIBUTE_DELETED) 33 #define ATTRIBUTE_IS_DELETED(flag) (flag & MU_ATTRIBUTE_DELETED)
33 #define ATTRIBUTE_IS_EQUAL(flag1, flag2) (flag1 == flag2) 34 #define ATTRIBUTE_IS_EQUAL(flag1, flag2) (flag1 == flag2)
...@@ -1033,7 +1034,7 @@ append_message_to_stream (mu_stream_t ostr, mu_message_t msg, ...@@ -1033,7 +1034,7 @@ append_message_to_stream (mu_stream_t ostr, mu_message_t msg,
1033 mbox_data_t mud, int flags) 1034 mbox_data_t mud, int flags)
1034 { 1035 {
1035 int status; 1036 int status;
1036 mu_stream_t istr; 1037 mu_stream_t istr, flt;
1037 1038
1038 status = msg_envelope_to_stream (ostr, msg); 1039 status = msg_envelope_to_stream (ostr, msg);
1039 if (status) 1040 if (status)
...@@ -1084,10 +1085,18 @@ append_message_to_stream (mu_stream_t ostr, mu_message_t msg, ...@@ -1084,10 +1085,18 @@ append_message_to_stream (mu_stream_t ostr, mu_message_t msg,
1084 if (status) 1085 if (status)
1085 return status; 1086 return status;
1086 } 1087 }
1087 status = mu_stream_copy (ostr, istr, 0, NULL); 1088
1088 mu_stream_destroy (&istr); 1089 status = mu_filter_create (&flt, istr, "FROM",
1090 MU_FILTER_ENCODE, MU_STREAM_READ);
1091 mu_stream_unref (istr);
1089 if (status == 0) 1092 if (status == 0)
1090 status = mu_stream_write (ostr, "\n", 1, NULL); 1093 {
1094 status = mu_stream_copy (ostr, flt, 0, NULL);
1095 mu_stream_destroy (&flt);
1096 if (status == 0)
1097 status = mu_stream_write (ostr, "\n", 1, NULL);
1098 }
1099
1091 return status; 1100 return status;
1092 } 1101 }
1093 1102
......