summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mailbox/filter_iconv.c108
1 files changed, 55 insertions, 53 deletions
diff --git a/mailbox/filter_iconv.c b/mailbox/filter_iconv.c
index 6470de791..c174271d3 100644
--- a/mailbox/filter_iconv.c
+++ b/mailbox/filter_iconv.c
@@ -50,24 +50,24 @@
enum _icvt_state
{
- state_closed,
- state_open,
- state_literal,
- state_octal,
- state_iconv_error,
- state_transport_error
+ state_closed, /* Filter is closed */
+ state_open, /* Filter is open and running in conversion mode */
+ state_copy_pass, /* Filter is open and running in copy-pass mode */
+ state_copy_octal, /* Filter is open and running in copy-octal mode */
+ state_iconv_error, /* A fatal iconv error has occurred */
+ state_transport_error /* A fatal transport error has occurred */
};
struct icvt_stream
{
stream_t stream; /* I/O stream */
+ int fallback_mode;
iconv_t cd; /* Conversion descriptor */
char *buf; /* Conversion buffer */
size_t bufsize; /* Size of buf */
size_t bufpos; /* Current position in buf */
enum _icvt_state state;
int ec; /* Error code */
- char ICONV_CONST *errp; /* Offending input if state == state_iconv_error */
char errbuf[128]; /* Error message buffer */
};
@@ -123,8 +123,9 @@ internal_icvt_read (stream_t stream, char *optr, size_t osize, size_t *pnbytes)
{
struct icvt_stream *s = stream_get_owner (stream);
size_t nbytes = 0;
- size_t cvtbytes = 0;
- int rc, status;
+ int rc, status = 0;
+ char *ob = optr;
+ size_t olen = osize;
if (s->bufpos == 0)
{
@@ -147,21 +148,22 @@ internal_icvt_read (stream_t stream, char *optr, size_t osize, size_t *pnbytes)
{
char ICONV_CONST *ib = s->buf;
size_t inlen = s->bufpos + nbytes;
- char *ob = optr + cvtbytes;
- size_t olen = osize - cvtbytes;
rc = iconv (s->cd, &ib, &inlen, &ob, &olen);
- cvtbytes += ib - s->buf;
+ if (ib > s->buf)
+ {
+ memmove (s->buf, ib, inlen);
+ s->bufpos = inlen;
+ }
+ else
+ s->bufpos += nbytes;
+
if (rc == -1)
{
if (errno == E2BIG)
{
- if (cvtbytes)
- {
- memmove (s->buf, ib, inlen);
- s->bufpos = inlen;
- break;
- }
+ if (ob > optr)
+ break;
else
{
s->ec = MU_ERR_BUFSPACE;
@@ -172,22 +174,24 @@ internal_icvt_read (stream_t stream, char *optr, size_t osize, size_t *pnbytes)
{
int flags = 0;
stream_get_flags (stream, &flags);
- if (flags & MU_STREAM_STRICT)
+ switch (s->fallback_mode)
{
+ case mu_fallback_none:
s->state = state_iconv_error;
s->ec = errno;
- s->errp = ib;
- if (cvtbytes)
- break;
- else
+ if (ob == optr)
return MU_ERR_FAILURE;
- }
- else
- {
- s->state = state_octal;
- memmove (s->buf, ib, inlen);
- s->bufpos = inlen;
- if (cvtbytes == 0)
+ break;
+
+ case mu_fallback_copy_pass:
+ s->state = state_copy_pass;
+ if (ob == optr)
+ return _icvt_read (stream, optr, osize, 0, pnbytes);
+ break;
+
+ case mu_fallback_copy_octal:
+ s->state = state_copy_octal;
+ if (ob == optr)
return _icvt_read (stream, optr, osize, 0, pnbytes);
break;
}
@@ -199,16 +203,9 @@ internal_icvt_read (stream_t stream, char *optr, size_t osize, size_t *pnbytes)
/* Try to reallocate temp buffer */
char *p = realloc (s->buf, s->bufsize + 128);
if (!p)
- {
- /* Rearrange the buffer anyway */
- memmove (s->buf, ib, inlen);
- s->bufpos = inlen;
- return ENOMEM;
- }
+ return ENOMEM;
s->bufsize += 128;
}
- memmove (s->buf, ib, inlen);
- s->bufpos = inlen;
continue;
}
else
@@ -219,7 +216,7 @@ internal_icvt_read (stream_t stream, char *optr, size_t osize, size_t *pnbytes)
}
}
}
- while (cvtbytes < osize
+ while (olen > 0
&& (status = stream_sequential_read (s->stream,
s->buf + s->bufpos,
s->bufsize - s->bufpos,
@@ -229,20 +226,20 @@ internal_icvt_read (stream_t stream, char *optr, size_t osize, size_t *pnbytes)
if (status)
{
s->state = state_transport_error;
- s->ec = rc;
- if (!cvtbytes)
+ s->ec = status;
+ if (ob == optr)
return MU_ERR_FAILURE;
}
if (*pnbytes)
- *pnbytes = cvtbytes;
+ *pnbytes = ob - optr;
return 0;
}
-#define ISPRINT(c) ((c)>=' '&&(c)<127)
+#define ISPRINT(c) (((c)>=' '&&(c)<127)||c=='\n')
static int
-octal_icvt_read (struct icvt_stream *s, char *optr, size_t osize, size_t *pnbytes)
+copy_octal (struct icvt_stream *s, char *optr, size_t osize, size_t *pnbytes)
{
size_t i, j;
int status;
@@ -263,7 +260,9 @@ octal_icvt_read (struct icvt_stream *s, char *optr, size_t osize, size_t *pnbyte
rdcount = s->bufsize;
}
- status = stream_sequential_read (s->stream, s->buf, rdcount - s->bufpos,
+ status = stream_sequential_read (s->stream,
+ s->buf + s->bufpos,
+ rdcount - s->bufpos,
&rdcount);
if (status)
{
@@ -276,7 +275,7 @@ octal_icvt_read (struct icvt_stream *s, char *optr, size_t osize, size_t *pnbyte
s->bufpos += rdcount;
}
- for (i = j = 0; i < osize && j < s->bufpos; i++)
+ for (i = j = 0; j < osize && i < s->bufpos; i++)
{
if (ISPRINT (*(unsigned char*)(s->buf+i)))
optr[j++] = s->buf[i];
@@ -296,7 +295,7 @@ octal_icvt_read (struct icvt_stream *s, char *optr, size_t osize, size_t *pnbyte
}
static int
-literal_icvt_read (struct icvt_stream *s, char *optr, size_t osize, size_t *pnbytes)
+copy_pass (struct icvt_stream *s, char *optr, size_t osize, size_t *pnbytes)
{
int status;
size_t nbytes;
@@ -340,11 +339,11 @@ _icvt_read (stream_t stream, char *optr, size_t osize,
case state_closed:
return EINVAL;
- case state_literal:
- return literal_icvt_read (s, optr, osize, pnbytes);
+ case state_copy_pass:
+ return copy_pass (s, optr, osize, pnbytes);
- case state_octal:
- return octal_icvt_read (s, optr, osize, pnbytes);
+ case state_copy_octal:
+ return copy_octal (s, optr, osize, pnbytes);
default:
break;
@@ -369,7 +368,8 @@ _icvt_strerror (stream_t stream, char **pstr)
{
case EILSEQ:
snprintf (s->errbuf, sizeof s->errbuf,
- _("Illegal multibyte sequence near %s"), s->errp);
+ _("Illegal multibyte sequence near %*.*s"),
+ s->bufpos, s->bufpos, s->buf);
break;
default:
@@ -411,7 +411,8 @@ _icvt_wait (stream_t stream, int *pflags, struct timeval *tvp)
int
filter_iconv_create (stream_t *s, stream_t transport,
- char *fromcode, char *tocode, int flags)
+ const char *fromcode, const char *tocode, int flags,
+ enum mu_iconv_fallback_mode fallback_mode)
{
struct icvt_stream *iptr;
iconv_t cd;
@@ -425,6 +426,7 @@ filter_iconv_create (stream_t *s, stream_t transport,
if (!iptr)
return ENOMEM;
iptr->stream = transport;
+ iptr->fallback_mode = fallback_mode;
iptr->cd = cd;
iptr->state = state_closed;
iptr->bufsize = 128;

Return to:

Send suggestions and report system problems to the System administrator.