summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeffrey Stedfast <fejj@ximian.com>2002-09-25 23:33:45 +0000
committerJeffrey Stedfast <fejj@src.gnome.org>2002-09-25 23:33:45 +0000
commitf528574e9ba0a53dae7f86409c49c94faeb71a16 (patch)
tree0aa22105a968ee1492b83d831952d715d30b1793
parent625d21d422efd3be7b6011b5e9173c3fa4aab5b2 (diff)
downloadevolution-data-server-f528574e9ba0a53dae7f86409c49c94faeb71a16.tar.gz
Handle EILSEQ by eating bytes in the input buffer until conversion is
2002-09-23 Jeffrey Stedfast <fejj@ximian.com> * camel-mime-filter-charset.c (complete): Handle EILSEQ by eating bytes in the input buffer until conversion is successful. The old behaviour aborted when it got EILSEQ and just dumped the raw data. (filter): Same. Fixes bug #30873.
-rw-r--r--camel/ChangeLog7
-rw-r--r--camel/camel-mime-filter-charset.c196
2 files changed, 115 insertions, 88 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index a58e1b201..b7972266b 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,3 +1,10 @@
+2002-09-23 Jeffrey Stedfast <fejj@ximian.com>
+
+ * camel-mime-filter-charset.c (complete): Handle EILSEQ by eating
+ bytes in the input buffer until conversion is successful. The old
+ behaviour aborted when it got EILSEQ and just dumped the raw data.
+ (filter): Same. Fixes bug #30873.
+
2002-09-24 Not Zed <NotZed@Ximian.com>
* camel-mime-utils.c (mail_list_magic[]): Changed the Mailing-List
diff --git a/camel/camel-mime-filter-charset.c b/camel/camel-mime-filter-charset.c
index f30047c96..28c4af4db 100644
--- a/camel/camel-mime-filter-charset.c
+++ b/camel/camel-mime-filter-charset.c
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Copyright (C) 2000 Ximian Inc.
*
@@ -84,119 +85,138 @@ reset(CamelMimeFilter *mf)
}
static void
-complete(CamelMimeFilter *mf, char *in, size_t len, size_t prespace, char **out, size_t *outlenptr, size_t *outprespace)
+complete(CamelMimeFilter *mf, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace)
{
- CamelMimeFilterCharset *f = (CamelMimeFilterCharset *)mf;
- size_t converted, inlen, outlen;
+ CamelMimeFilterCharset *charset = (CamelMimeFilterCharset *)mf;
+ size_t inleft, outleft, converted = 0;
const char *inbuf;
char *outbuf;
- if (f->ic == (iconv_t) -1) {
- goto donothing;
- }
-
- /* FIXME: there's probably a safer way to size this ...? */
- /* We could always resize if we run out of room in outbuf (but it'd be nice not
- to have to) */
- camel_mime_filter_set_size(mf, len*5+16, FALSE);
- inbuf = in;
- inlen = len;
+ if (charset->ic == (iconv_t) -1)
+ goto noop;
+
+ camel_mime_filter_set_size (mf, len * 5 + 16, FALSE);
outbuf = mf->outbuf;
- outlen = mf->outsize;
-
- /* temporary fix to find another bug somewhere */
- d(memset(outbuf, 0, outlen));
-
- if (inlen>0) {
- converted = e_iconv(f->ic, &inbuf, &inlen, &outbuf, &outlen);
- if (converted == (size_t) -1) {
- if (errno != EINVAL) {
- g_warning("error occured converting: %s", strerror(errno));
- goto donothing;
+ outleft = mf->outsize;
+
+ inbuf = in;
+ inleft = len;
+
+ if (inleft > 0) {
+ do {
+ converted = e_iconv (charset->ic, &inbuf, &inleft, &outbuf, &outleft);
+ if (converted == (size_t) -1) {
+ if (errno == E2BIG) {
+ /*
+ * E2BIG There is not sufficient room at *outbuf.
+ *
+ * We just need to grow our outbuffer and try again.
+ */
+
+ converted = outbuf - mf->outbuf;
+ camel_mime_filter_set_size (mf, inleft * 5 + mf->outsize + 16, TRUE);
+ outbuf = mf->outbuf + converted;
+ outleft = mf->outsize - converted;
+ } else if (errno == EILSEQ) {
+ /*
+ * EILSEQ An invalid multibyte sequence has been encountered
+ * in the input.
+ *
+ * What we do here is eat the invalid bytes in the sequence and continue
+ */
+
+ inbuf++;
+ inleft--;
+ } else if (errno == EINVAL) {
+ /*
+ * EINVAL An incomplete multibyte sequence has been encoun­
+ * tered in the input.
+ *
+ * We assume that this can only happen if we've run out of
+ * bytes for a multibyte sequence, if not we're in trouble.
+ */
+
+ break;
+ } else
+ goto noop;
}
- }
-
- if (inlen>0) {
- g_warning("Output lost in character conversion, invalid sequence encountered?");
- }
- }
-
- /* this 'resets' the output stream, returning back to the initial
- shift state for multishift charactersets */
- converted = e_iconv(f->ic, NULL, 0, &outbuf, &outlen);
- if (converted == (size_t) -1) {
- g_warning("Conversion failed to complete: %s", strerror(errno));
+ } while (((int) inleft) > 0);
}
-
- /* debugging assertion - check for NUL's in output */
- d({
- int i;
-
- for (i=0;i<(mf->outsize - outlen);i++) {
- g_assert(mf->outbuf[i]);
- }
- });
-
+
+ /* flush the iconv conversion */
+ e_iconv (charset->ic, NULL, NULL, &outbuf, &outleft);
+
*out = mf->outbuf;
- *outlenptr = mf->outsize - outlen;
+ *outlen = mf->outsize - outleft;
*outprespace = mf->outpre;
+
return;
-
-donothing:
+
+ noop:
+
*out = in;
- *outlenptr = len;
+ *outlen = len;
*outprespace = prespace;
}
static void
-filter(CamelMimeFilter *mf, char *in, size_t len, size_t prespace, char **out, size_t *outlenptr, size_t *outprespace)
+filter(CamelMimeFilter *mf, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace)
{
- CamelMimeFilterCharset *f = (CamelMimeFilterCharset *)mf;
- size_t converted, inlen, outlen;
+ CamelMimeFilterCharset *charset = (CamelMimeFilterCharset *)mf;
+ size_t inleft, outleft, converted = 0;
const char *inbuf;
char *outbuf;
-
- if (f->ic == (iconv_t) -1) {
- goto donothing;
- }
-
- /* FIXME: there's probably a safer way to size this ...? */
- camel_mime_filter_set_size(mf, len*5+16, FALSE);
+
+ if (charset->ic == (iconv_t) -1)
+ goto noop;
+
+ camel_mime_filter_set_size (mf, len * 5 + 16, FALSE);
+ outbuf = mf->outbuf + converted;
+ outleft = mf->outsize - converted;
+
inbuf = in;
- inlen = len;
- outbuf = mf->outbuf;
- outlen = mf->outsize;
- converted = e_iconv(f->ic, &inbuf, &inlen, &outbuf, &outlen);
- if (converted == (size_t) -1) {
- if (errno != EINVAL) {
- g_warning("error occured converting: %s", strerror(errno));
- goto donothing;
+ inleft = len;
+
+ do {
+ converted = e_iconv (charset->ic, &inbuf, &inleft, &outbuf, &outleft);
+ if (converted == (size_t) -1) {
+ if (errno == E2BIG || errno == EINVAL)
+ break;
+
+ if (errno == EILSEQ) {
+ /*
+ * EILSEQ An invalid multibyte sequence has been encountered
+ * in the input.
+ *
+ * What we do here is eat the invalid bytes in the sequence and continue
+ */
+
+ inbuf++;
+ inleft--;
+ } else {
+ /* unknown error condition */
+ goto noop;
+ }
}
+ } while (((int) inleft) > 0);
+
+ if (((int) inleft) > 0) {
+ /* We've either got an E2BIG or EINVAL. Save the
+ remainder of the buffer as we'll process this next
+ time through */
+ camel_mime_filter_backup (mf, inbuf, inleft);
}
-
- /*
- NOTE: This assumes EINVAL only occurs because we ran out of
- bytes for a multibyte sequence, if not, we're in trouble.
- */
-
- /* This is to fix a bug in at least 1 version of glibc iconv: we get EINVAL and
- it reads past the input and returns a converted length of -1 ... so discard
- any overruns as failed */
- if (((int)inlen) < 0)
- inlen = 0;
-
- if (inlen>0) {
- camel_mime_filter_backup(mf, inbuf, inlen);
- }
-
+
*out = mf->outbuf;
- *outlenptr = mf->outsize - outlen;
+ *outlen = outbuf - mf->outbuf;
*outprespace = mf->outpre;
+
return;
-
-donothing:
+
+ noop:
+
*out = in;
- *outlenptr = len;
+ *outlen = len;
*outprespace = prespace;
}