1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2000 Ximian Inc.
5 * Authors: Michael Zucchi <notzed@ximian.com>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of version 2 of the GNU Lesser General Public
9 * License as published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
30 #include <libedataserver/e-iconv.h>
32 #include "camel-charset-map.h"
33 #include "camel-mime-filter-charset.h"
38 static void camel_mime_filter_charset_class_init (CamelMimeFilterCharsetClass *klass);
39 static void camel_mime_filter_charset_init (CamelMimeFilterCharset *obj);
40 static void camel_mime_filter_charset_finalize (CamelObject *o);
42 static CamelMimeFilterClass *camel_mime_filter_charset_parent;
45 camel_mime_filter_charset_get_type (void)
47 static CamelType type = CAMEL_INVALID_TYPE;
49 if (type == CAMEL_INVALID_TYPE) {
50 type = camel_type_register (camel_mime_filter_get_type (), "CamelMimeFilterCharset",
51 sizeof (CamelMimeFilterCharset),
52 sizeof (CamelMimeFilterCharsetClass),
53 (CamelObjectClassInitFunc) camel_mime_filter_charset_class_init,
55 (CamelObjectInitFunc) camel_mime_filter_charset_init,
56 (CamelObjectFinalizeFunc) camel_mime_filter_charset_finalize);
63 camel_mime_filter_charset_finalize(CamelObject *o)
65 CamelMimeFilterCharset *f = (CamelMimeFilterCharset *)o;
69 if (f->ic != (iconv_t) -1) {
70 e_iconv_close (f->ic);
76 reset(CamelMimeFilter *mf)
78 CamelMimeFilterCharset *f = (CamelMimeFilterCharset *)mf;
83 /* what happens with the output bytes if this resets the state? */
84 if (f->ic != (iconv_t) -1) {
86 e_iconv (f->ic, NULL, 0, &buffer, &outlen);
91 complete(CamelMimeFilter *mf, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace)
93 CamelMimeFilterCharset *charset = (CamelMimeFilterCharset *)mf;
94 size_t inleft, outleft, converted = 0;
98 if (charset->ic == (iconv_t) -1)
101 camel_mime_filter_set_size (mf, len * 5 + 16, FALSE);
103 outleft = mf->outsize;
110 converted = e_iconv (charset->ic, &inbuf, &inleft, &outbuf, &outleft);
111 if (converted == (size_t) -1) {
112 if (errno == E2BIG) {
114 * E2BIG There is not sufficient room at *outbuf.
116 * We just need to grow our outbuffer and try again.
119 converted = outbuf - mf->outbuf;
120 camel_mime_filter_set_size (mf, inleft * 5 + mf->outsize + 16, TRUE);
121 outbuf = mf->outbuf + converted;
122 outleft = mf->outsize - converted;
123 } else if (errno == EILSEQ) {
125 * EILSEQ An invalid multibyte sequence has been encountered
128 * What we do here is eat the invalid bytes in the sequence and continue
133 } else if (errno == EINVAL) {
135 * EINVAL An incomplete multibyte sequence has been encounĀ
136 * tered in the input.
138 * We assume that this can only happen if we've run out of
139 * bytes for a multibyte sequence, if not we're in trouble.
146 } while (((int) inleft) > 0);
149 /* flush the iconv conversion */
150 e_iconv (charset->ic, NULL, NULL, &outbuf, &outleft);
153 *outlen = mf->outsize - outleft;
154 *outprespace = mf->outpre;
162 *outprespace = prespace;
166 filter(CamelMimeFilter *mf, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace)
168 CamelMimeFilterCharset *charset = (CamelMimeFilterCharset *)mf;
169 size_t inleft, outleft, converted = 0;
173 if (charset->ic == (iconv_t) -1)
176 camel_mime_filter_set_size (mf, len * 5 + 16, FALSE);
177 outbuf = mf->outbuf + converted;
178 outleft = mf->outsize - converted;
184 converted = e_iconv (charset->ic, &inbuf, &inleft, &outbuf, &outleft);
185 if (converted == (size_t) -1) {
186 if (errno == E2BIG || errno == EINVAL)
189 if (errno == EILSEQ) {
191 * EILSEQ An invalid multibyte sequence has been encountered
194 * What we do here is eat the invalid bytes in the sequence and continue
200 /* unknown error condition */
204 } while (((int) inleft) > 0);
206 if (((int) inleft) > 0) {
207 /* We've either got an E2BIG or EINVAL. Save the
208 remainder of the buffer as we'll process this next
210 camel_mime_filter_backup (mf, inbuf, inleft);
214 *outlen = outbuf - mf->outbuf;
215 *outprespace = mf->outpre;
223 *outprespace = prespace;
227 camel_mime_filter_charset_class_init (CamelMimeFilterCharsetClass *klass)
229 CamelMimeFilterClass *filter_class = (CamelMimeFilterClass *) klass;
231 camel_mime_filter_charset_parent = CAMEL_MIME_FILTER_CLASS (camel_type_get_global_classfuncs (camel_mime_filter_get_type ()));
233 filter_class->reset = reset;
234 filter_class->filter = filter;
235 filter_class->complete = complete;
239 camel_mime_filter_charset_init (CamelMimeFilterCharset *obj)
241 obj->ic = (iconv_t)-1;
246 * camel_mime_filter_charset_new:
248 * Create a new #CamelMimeFilterCharset object.
250 * Returns a new #CamelMimeFilterCharset object
252 CamelMimeFilterCharset *
253 camel_mime_filter_charset_new (void)
255 return CAMEL_MIME_FILTER_CHARSET (camel_object_new (camel_mime_filter_charset_get_type ()));
260 * camel_mime_filter_charset_new_convert:
261 * @from_charset: charset to convert from
262 * @to_charset: charset to convert to
264 * Create a new #CamelMimeFiletrCharset object to convert text from
265 * @from_charset to @to_charset.
267 * Returns a new #CamelMimeFilterCharset object
269 CamelMimeFilterCharset *
270 camel_mime_filter_charset_new_convert (const char *from_charset, const char *to_charset)
272 CamelMimeFilterCharset *new;
274 new = CAMEL_MIME_FILTER_CHARSET (camel_object_new (camel_mime_filter_charset_get_type ()));
276 new->ic = e_iconv_open (to_charset, from_charset);
277 if (new->ic == (iconv_t) -1) {
278 w(g_warning ("Cannot create charset conversion from %s to %s: %s",
279 from_charset ? from_charset : "(null)",
280 to_charset ? to_charset : "(null)",
281 g_strerror (errno)));
282 camel_object_unref (new);
285 new->from = g_strdup (from_charset);
286 new->to = g_strdup (to_charset);