Commit 1f1dca41 1f1dca416897539ad734149945482fecf6f066e5 by Sergey Poznyakoff

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.
1 parent 19e30116
...@@ -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,
......
...@@ -29,6 +29,7 @@ libfilter_la_SOURCES =\ ...@@ -29,6 +29,7 @@ libfilter_la_SOURCES =\
29 fltchain.c\ 29 fltchain.c\
30 fromflt.c\ 30 fromflt.c\
31 header.c\ 31 header.c\
32 iconvflt.c\
32 inline-comment.c\ 33 inline-comment.c\
33 linecon.c\ 34 linecon.c\
34 linelenflt.c\ 35 linelenflt.c\
......
...@@ -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;
......
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;