Re-implement iconv convertor as a regular filter.
* include/mailutils/filter.h (mu_iconv_filter): New extern. * libmailutils/filter/iconvflt.c: New file. * libmailutils/filter/Makefile.am (libfilter_la_SOURCES): Add iconvflt.c * libmailutils/filter/filter.c (mu_filter_get_list): Register mu_iconv_filter.
Showing
4 changed files
with
255 additions
and
1 deletions
... | @@ -120,7 +120,8 @@ extern mu_filter_record_t mu_inline_comment_filter; | ... | @@ -120,7 +120,8 @@ extern mu_filter_record_t mu_inline_comment_filter; |
120 | extern mu_filter_record_t mu_header_filter; | 120 | extern mu_filter_record_t mu_header_filter; |
121 | extern mu_filter_record_t mu_linecon_filter; | 121 | extern mu_filter_record_t mu_linecon_filter; |
122 | extern mu_filter_record_t mu_linelen_filter; | 122 | extern mu_filter_record_t mu_linelen_filter; |
123 | 123 | extern mu_filter_record_t mu_iconv_filter; | |
124 | |||
124 | enum mu_iconv_fallback_mode | 125 | enum mu_iconv_fallback_mode |
125 | { | 126 | { |
126 | mu_fallback_none, | 127 | mu_fallback_none, | ... | ... |
... | @@ -82,6 +82,7 @@ mu_filter_get_list (mu_list_t *plist) | ... | @@ -82,6 +82,7 @@ mu_filter_get_list (mu_list_t *plist) |
82 | mu_list_append (filter_list, mu_header_filter); | 82 | mu_list_append (filter_list, mu_header_filter); |
83 | mu_list_append (filter_list, mu_linecon_filter); | 83 | mu_list_append (filter_list, mu_linecon_filter); |
84 | mu_list_append (filter_list, mu_linelen_filter); | 84 | mu_list_append (filter_list, mu_linelen_filter); |
85 | mu_list_append (filter_list, mu_iconv_filter); | ||
85 | /* FIXME: add the default encodings? */ | 86 | /* FIXME: add the default encodings? */ |
86 | } | 87 | } |
87 | *plist = filter_list; | 88 | *plist = filter_list; | ... | ... |
libmailutils/filter/iconvflt.c
0 → 100644
1 | /* GNU Mailutils -- a suite of utilities for electronic mail | ||
2 | Copyright (C) 2004, 2005, 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, see | ||
16 | <http://www.gnu.org/licenses/>. */ | ||
17 | |||
18 | /* Iconv filter: converts input between two charsets. | ||
19 | |||
20 | This filter operates in decode mode only. Initialization sequence | ||
21 | requires two arguments: the name of the input encoding and that | ||
22 | of the output encoding. Optional third argument specifies what | ||
23 | to do when an illegal character sequence is encountered on input. | ||
24 | Possible values are: | ||
25 | |||
26 | none - return failure and stop further conversions; | ||
27 | copy-pass - copy the offending character to the output verbatim; | ||
28 | copy-octal - represent it as a C octal sequence (\NNN). | ||
29 | |||
30 | The default is "copy-octal", unless overridden by mu_default_fallback_mode | ||
31 | setting (which see). | ||
32 | */ | ||
33 | |||
34 | #ifdef HAVE_CONFIG_H | ||
35 | # include <config.h> | ||
36 | #endif | ||
37 | |||
38 | #include <stdlib.h> | ||
39 | #include <stdio.h> | ||
40 | #include <string.h> | ||
41 | #include <errno.h> | ||
42 | #include <mailutils/stream.h> | ||
43 | #include <mailutils/sys/stream.h> | ||
44 | #include <mailutils/filter.h> | ||
45 | #include <mailutils/errno.h> | ||
46 | #include <mailutils/cstr.h> | ||
47 | #include <mailutils/cctype.h> | ||
48 | #include <mailutils/util.h> | ||
49 | |||
50 | #ifdef HAVE_ICONV_H | ||
51 | # include <iconv.h> | ||
52 | #endif | ||
53 | |||
54 | #ifndef ICONV_CONST | ||
55 | # define ICONV_CONST | ||
56 | #endif | ||
57 | |||
58 | #ifndef HAVE_ICONV | ||
59 | # undef iconv_open | ||
60 | # define iconv_open(tocode, fromcode) ((iconv_t) -1) | ||
61 | |||
62 | # undef iconv | ||
63 | # define iconv(cd, inbuf, inbytesleft, outbuf, outbytesleft) (errno = EILSEQ, (size_t) -1) | ||
64 | |||
65 | # undef iconv_close | ||
66 | # define iconv_close(cd) 0 | ||
67 | |||
68 | #endif | ||
69 | |||
70 | struct _icvt_filter | ||
71 | { | ||
72 | char *fromcode; | ||
73 | char *tocode; | ||
74 | enum mu_iconv_fallback_mode fallback_mode; | ||
75 | iconv_t cd; /* Conversion descriptor */ | ||
76 | }; | ||
77 | |||
78 | static enum mu_filter_result | ||
79 | _icvt_decoder (void *xd, | ||
80 | enum mu_filter_command cmd, | ||
81 | struct mu_filter_io *iobuf) | ||
82 | { | ||
83 | struct _icvt_filter *_icvt = xd; | ||
84 | char *ip, *op; | ||
85 | size_t ilen, olen; | ||
86 | int rc; | ||
87 | |||
88 | switch (cmd) | ||
89 | { | ||
90 | case mu_filter_init: | ||
91 | if (mu_c_strcasecmp (_icvt->fromcode, _icvt->tocode) == 0) | ||
92 | _icvt->cd = (iconv_t) -1; | ||
93 | else | ||
94 | { | ||
95 | iconv_t cd = iconv_open (_icvt->tocode, _icvt->fromcode); | ||
96 | if (cd == (iconv_t) -1) | ||
97 | return mu_filter_failure; | ||
98 | _icvt->cd = cd; | ||
99 | } | ||
100 | return mu_filter_ok; | ||
101 | |||
102 | case mu_filter_done: | ||
103 | iconv_close (_icvt->cd); | ||
104 | free (_icvt->fromcode); | ||
105 | free (_icvt->tocode); | ||
106 | return mu_filter_ok; | ||
107 | |||
108 | default: | ||
109 | break; | ||
110 | } | ||
111 | |||
112 | if (_icvt->cd == (iconv_t) -1) | ||
113 | { | ||
114 | size_t len = iobuf->isize; | ||
115 | if (len > iobuf->osize) | ||
116 | len = iobuf->osize; | ||
117 | memcpy (iobuf->output, iobuf->input, len); | ||
118 | iobuf->isize = len; | ||
119 | iobuf->osize = len; | ||
120 | return mu_filter_ok; | ||
121 | } | ||
122 | |||
123 | ip = (char*) iobuf->input; | ||
124 | ilen = iobuf->isize; | ||
125 | op = iobuf->output; | ||
126 | olen = iobuf->osize; | ||
127 | again: | ||
128 | rc = iconv (_icvt->cd, &ip, &ilen, &op, &olen); | ||
129 | if (rc == -1) | ||
130 | { | ||
131 | switch (errno) | ||
132 | { | ||
133 | case E2BIG: | ||
134 | iobuf->osize += 16; | ||
135 | return mu_filter_moreoutput; | ||
136 | |||
137 | case EINVAL: | ||
138 | /* An incomplete multibyte sequence is encountered in the input */ | ||
139 | if (ilen == iobuf->isize) | ||
140 | { | ||
141 | iobuf->isize++; | ||
142 | return mu_filter_moreinput; | ||
143 | } | ||
144 | break; | ||
145 | |||
146 | case EILSEQ: | ||
147 | switch (_icvt->fallback_mode) | ||
148 | { | ||
149 | case mu_fallback_none: | ||
150 | return mu_filter_failure; | ||
151 | |||
152 | case mu_fallback_copy_pass: | ||
153 | *op++ = *ip++; | ||
154 | ilen--; | ||
155 | olen--; | ||
156 | break; | ||
157 | |||
158 | case mu_fallback_copy_octal: | ||
159 | if (mu_isprint (*ip)) | ||
160 | { | ||
161 | *op++ = *ip++; | ||
162 | ilen--; | ||
163 | olen--; | ||
164 | } | ||
165 | else | ||
166 | { | ||
167 | if (olen < 4) | ||
168 | { | ||
169 | iobuf->osize = 4; | ||
170 | return mu_filter_moreoutput; | ||
171 | } | ||
172 | sprintf (op, "\\%03o", *(unsigned char*)ip); | ||
173 | op += 4; | ||
174 | olen -= 4; | ||
175 | ip++; | ||
176 | ilen--; | ||
177 | } | ||
178 | } | ||
179 | if (ilen && olen) | ||
180 | goto again; | ||
181 | break; | ||
182 | |||
183 | default: | ||
184 | return mu_filter_failure; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | iobuf->isize = ip - iobuf->input; | ||
189 | iobuf->osize = op - iobuf->output; | ||
190 | return mu_filter_ok; | ||
191 | } | ||
192 | |||
193 | static int | ||
194 | alloc_state (void **pret, int mode MU_ARG_UNUSED, int argc, const char **argv) | ||
195 | { | ||
196 | struct _icvt_filter *flt; | ||
197 | const char *from; | ||
198 | const char *to; | ||
199 | enum mu_iconv_fallback_mode fallback_mode = mu_default_fallback_mode; | ||
200 | |||
201 | if (argc < 3) | ||
202 | return EINVAL; /* FIXME: Provide some defaults? */ | ||
203 | if (argc > 4) | ||
204 | return EINVAL; | ||
205 | |||
206 | from = argv[1]; | ||
207 | to = argv[2]; | ||
208 | |||
209 | if (argc == 4) | ||
210 | { | ||
211 | const char *str = argv[3]; | ||
212 | if (strcmp (str, "none") == 0) | ||
213 | fallback_mode = mu_fallback_none; | ||
214 | else if (strcmp (str, "copy-pass") == 0) | ||
215 | fallback_mode = mu_fallback_copy_pass; | ||
216 | else if (strcmp (str, "copy-octal") == 0) | ||
217 | fallback_mode = mu_fallback_copy_octal; | ||
218 | else | ||
219 | return EINVAL; | ||
220 | } | ||
221 | |||
222 | flt = calloc (1, sizeof (*flt)); | ||
223 | if (!flt) | ||
224 | return ENOMEM; | ||
225 | flt->fromcode = strdup (from); | ||
226 | if (!flt->fromcode) | ||
227 | { | ||
228 | free (flt); | ||
229 | return ENOMEM; | ||
230 | } | ||
231 | flt->tocode = strdup (to); | ||
232 | if (!flt->tocode) | ||
233 | { | ||
234 | free (flt->fromcode); | ||
235 | free (flt); | ||
236 | return ENOMEM; | ||
237 | } | ||
238 | flt->fallback_mode = fallback_mode; | ||
239 | flt->cd = (iconv_t) -1; | ||
240 | *pret = flt; | ||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | static struct _mu_filter_record _iconv_filter = { | ||
245 | "ICONV", | ||
246 | alloc_state, | ||
247 | NULL, | ||
248 | _icvt_decoder | ||
249 | }; | ||
250 | |||
251 | mu_filter_record_t mu_iconv_filter = &_iconv_filter; |
-
Please register or sign in to post a comment