}
-/*************************************************************
- * General decoder framework
- * Used in handler.c for converting to mutt's Charset
- */
-
-#define MIN(a,b) (((a) <= (b)) ? (a): (b))
-
-DECODER *mutt_open_decoder (const char *src, const char *dest)
-{
- DECODER *d = safe_calloc (1, sizeof (DECODER));;
-
- d->in.size = DECODER_BUFFSIZE;
- d->out.size = DECODER_BUFFSIZE;
-
- if (dest && src && (d->cd = mutt_iconv_open (dest, src)) != (iconv_t)-1)
- {
- d->_in = &d->in;
- d->outrepl = mutt_is_utf8 (dest) ? "\357\277\275" : "?";
- }
- else
- {
- d->just_take_id = 1;
- d->_in = &d->out;
- }
- return d;
-}
-
-void mutt_free_decoder (DECODER **dpp)
-{
- safe_free ((void **) dpp);
-}
-
-static void _process_data (DECODER *d, short force)
-{
- if (force) d->forced = 1;
-
- if (!d->just_take_id)
- {
- const char *ib = d->in.buff;
- size_t ibl = d->in.used;
- char *ob = d->out.buff + d->out.used;
- size_t obl = d->out.size - d->out.used;
-
- mutt_iconv (d->cd, &ib, &ibl, &ob, &obl, 0, d->outrepl);
- memmove (d->in.buff, ib, ibl);
- d->in.used = ibl;
- d->out.used = d->out.size - obl;
- }
-}
-
-void mutt_decoder_push (DECODER *d, void *_buff, size_t blen, size_t *taken)
-{
- if (!_buff || !blen)
- {
- _process_data (d, 1);
- return;
- }
-
- if ((*taken = MIN(blen, d->_in->size - d->_in->used)))
- {
- memcpy (d->_in->buff + d->_in->used, _buff, *taken);
- d->_in->used += *taken;
- }
-}
-
-int mutt_decoder_push_one (DECODER *d, char c)
-{
- if (d->_in->used == d->_in->size)
- return -1;
-
- d->_in->buff[d->_in->used++] = c;
- return 0;
-}
-
-void mutt_decoder_pop (DECODER *d, void *_buff, size_t blen, size_t *popped)
-{
- unsigned char *buff = _buff;
-
- _process_data (d, 0);
-
- if ((*popped = MIN (blen, d->out.used)))
- {
- memcpy (buff, d->out.buff, *popped);
- memmove (d->out.buff, d->out.buff + *popped, d->out.used - *popped);
- d->out.used -= *popped;
- }
-}
-
-void mutt_decoder_pop_to_state (DECODER *d, STATE *s)
-{
- char tmp[DECODER_BUFFSIZE];
- size_t i, l;
-
- if (s->prefix)
- {
- do
- {
- mutt_decoder_pop (d, tmp, sizeof (tmp), &l);
- for (i = 0; i < l; i++)
- state_prefix_putc (tmp[i], s);
- }
- while (l > 0);
- }
- else
- {
- do
- {
- mutt_decoder_pop (d, tmp, sizeof (tmp), &l);
- fwrite (tmp, l, 1, s->fpout);
- }
- while (l > 0);
- }
-}
-
-
-int mutt_recode_file (const char *fname, const char *src, const char *dest)
-{
- FILE *fp, *tmpfp;
- char tempfile[_POSIX_PATH_MAX];
- char buffer[1024];
- char tmp[1024];
- int c;
- int rv = -1;
- int source_file_is_unchanged = 1;
-
- size_t lf, lpu, lpo;
- char *t;
- DECODER *dec;
-
- if ((fp = fopen (fname, "r+")) == NULL)
- {
- mutt_error (_("Can't open %s: %s."), fname, strerror (errno));
- return -1;
- }
-
- mutt_mktemp (tempfile);
- if ((tmpfp = safe_fopen (tempfile, "w+")) == NULL)
- {
- mutt_error (_("Can't open %s: %s."), tempfile, strerror (errno));
- fclose (fp);
- return -1;
- }
-
- dec = mutt_open_decoder (src, dest);
-
- while ((lf = fread (buffer, 1, sizeof (buffer), fp)) > 0)
- {
- for (t = buffer; lf; t += lpu)
- {
- mutt_decoder_push (dec, t, lf, &lpu);
- lf -= lpu;
-
- do
- {
- mutt_decoder_pop (dec, tmp, sizeof (tmp), &lpo);
- if (lpo)
- {
- if (fwrite (tmp, lpo, 1, tmpfp) == EOF)
- goto bail;
- }
- }
- while (lpo);
- }
- }
- if (lf == EOF && !feof(fp))
- {
- goto bail;
- }
-
- mutt_decoder_push (dec, NULL, 0, NULL);
- do
- {
- mutt_decoder_pop (dec, tmp, sizeof (tmp), &lpo);
- if (lpo)
- {
- if (fwrite (tmp, lpo, 1, tmpfp) == EOF)
- goto bail;
- }
- }
- while (lpo);
-
- mutt_free_decoder (&dec);
-
- fclose (fp); fp = NULL;
- rewind (tmpfp);
-
-
- source_file_is_unchanged = 0;
-
- /* don't use safe_fopen here - we're just going
- * to overwrite the old file.
- */
- if ((fp = fopen (fname, "w")) == NULL)
- goto bail;
-
- while ((c = fgetc (tmpfp)) != EOF)
- if (fputc (c, fp) == EOF)
- goto bail;
-
- rv = 0;
- unlink (tempfile);
-
-bail:
- if (rv == -1)
- {
- if (source_file_is_unchanged)
- {
- mutt_error (_("Error while recoding %s. "
- "Leave it unchanged."),
- fname);
- }
- else
- {
- mutt_error (_("Error while recoding %s. "
- "See %s for recovering your data."),
- fname, tempfile);
- }
- }
-
- if (fp) fclose (fp);
- if (tmpfp) fclose (tmpfp);
- return rv;
-}
-
-
/*
* Convert a string
* Used in rfc2047.c and rfc2231.c
#endif
+#define BUFI_SIZE 1000
+#define BUFO_SIZE 2000
+
typedef void handler_f (BODY *, STATE *);
typedef handler_f *handler_t;
41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
};
-void mutt_decode_xbit (STATE *s, BODY *b, int istext, DECODER *dec)
+static void state_prefix_put (const char *d, size_t dlen, STATE *s)
+{
+ if (s->prefix)
+ while (dlen--)
+ state_prefix_putc (*d++, s);
+ else
+ fwrite (d, dlen, 1, s->fpout);
+}
+
+static void convert_to_state(iconv_t cd, char *bufi, size_t *l, STATE *s)
+{
+ char bufo[BUFO_SIZE];
+ const char *ib;
+ char *ob;
+ size_t ibl, obl;
+
+ if (!bufi)
+ {
+ if (cd != (iconv_t)(-1))
+ {
+ ob = bufo, obl = sizeof (bufo);
+ iconv (cd, 0, 0, &ob, &obl);
+ if (ob != bufo)
+ state_prefix_put (bufo, ob - bufo, s);
+ }
+ return;
+ }
+
+ if (cd == (iconv_t)(-1))
+ {
+ state_prefix_put (bufi, *l, s);
+ *l = 0;
+ return;
+ }
+
+ ib = bufi, ibl = *l;
+ for (;;)
+ {
+ ob = bufo, obl = sizeof (bufo);
+ mutt_iconv (cd, &ib, &ibl, &ob, &obl, 0, "?");
+ if (ob == bufo)
+ break;
+ state_prefix_put (bufo, ob - bufo, s);
+ }
+ memmove (bufi, ib, ibl);
+ *l = ibl;
+}
+
+void mutt_decode_xbit (STATE *s, BODY *b, int istext, iconv_t cd)
{
long len = b->length;
int c, ch;
- int l = 0;
+ char bufi[BUFI_SIZE];
+ size_t l = 0;
if (istext)
{
ungetc(ch, s->fpin);
}
- mutt_decoder_push_one (dec, c);
- if (l++ == 1024)
- {
- mutt_decoder_pop_to_state (dec, s);
- l = 0;
- }
+ bufi[l++] = c;
+ if (l == sizeof (bufi))
+ convert_to_state (cd, bufi, &l, s);
}
- mutt_decoder_push (dec, NULL, 0, NULL);
- mutt_decoder_pop_to_state (dec, s);
+ convert_to_state (cd, bufi, &l, s);
+ convert_to_state (cd, 0, 0, s);
state_reset_prefix (s);
}
return ch;
}
-void mutt_decode_quoted (STATE *s, BODY *b, int istext, DECODER *dec)
+void mutt_decode_quoted (STATE *s, BODY *b, int istext, iconv_t cd)
{
long len = b->length;
int ch;
- int l = 0;
+ char bufi[BUFI_SIZE];
+ size_t l = 0;
state_set_prefix(s);
if(ch != EOF)
{
- mutt_decoder_push_one (dec, ch);
- if (l++ == 1024)
- {
- mutt_decoder_pop_to_state (dec, s);
- l = 0;
- }
+ bufi[l++] = ch;
+ if (l == sizeof (bufi))
+ convert_to_state (cd, bufi, &l, s);
}
}
- mutt_decoder_push (dec, NULL, 0, NULL);
- mutt_decoder_pop_to_state (dec, s);
+ convert_to_state (cd, bufi, &l, s);
+ convert_to_state (cd, 0, 0, s);
state_reset_prefix(s);
}
-void mutt_decode_base64 (STATE *s, BODY *b, int istext, DECODER *dec)
+void mutt_decode_base64 (STATE *s, BODY *b, int istext, iconv_t cd)
{
long len = b->length;
char buf[5];
int c1, c2, c3, c4, ch, cr = 0, i;
+ char bufi[BUFI_SIZE];
size_t l = 0;
buf[4] = 0;
ch = (c1 << 2) | (c2 >> 4);
if (cr && ch != '\n')
- mutt_decoder_push_one (dec, '\r');
+ bufi[l++] = '\r';
cr = 0;
if (istext && ch == '\r')
cr = 1;
else
- mutt_decoder_push_one (dec, ch);
+ bufi[l++] = ch;
if (buf[2] == '=')
break;
ch = ((c2 & 0xf) << 4) | (c3 >> 2);
if (cr && ch != '\n')
- mutt_decoder_push_one (dec, '\r');
+ bufi[l++] = '\r';
cr = 0;
if (istext && ch == '\r')
cr = 1;
else
- mutt_decoder_push_one (dec, ch);
+ bufi[l++] = ch;
if (buf[3] == '=') break;
c4 = base64val (buf[3]);
ch = ((c3 & 0x3) << 6) | c4;
if (cr && ch != '\n')
- mutt_decoder_push_one (dec, '\r');
+ bufi[l++] = '\r';
cr = 0;
if (istext && ch == '\r')
cr = 1;
else
- mutt_decoder_push_one (dec, ch);
+ bufi[l++] = ch;
- if ((l += 3) >= 1024)
- {
- mutt_decoder_pop_to_state (dec, s);
- l = 0;
- }
+ if (l + 8 >= sizeof (bufi))
+ convert_to_state (cd, bufi, &l, s);
}
- if (cr) mutt_decoder_push_one (dec, '\r');
-
- mutt_decoder_push (dec, NULL, 0, NULL);
- mutt_decoder_pop_to_state (dec, s);
+ if (cr) bufi[l++] = '\r';
+
+ convert_to_state (cd, bufi, &l, s);
+ convert_to_state (cd, 0, 0, s);
state_reset_prefix(s);
}
return ch - 32;
}
-void mutt_decode_uuencoded (STATE *s, BODY *b, int istext, DECODER *dec)
+void mutt_decode_uuencoded (STATE *s, BODY *b, int istext, iconv_t cd)
{
char tmps[SHORT_STRING];
char linelen, c, l, out;
char *pt;
long len = b->length;
+ char bufi[BUFI_SIZE];
+ size_t k;
if(istext)
state_set_prefix(s);
out = decode_byte (*pt) << l;
pt++;
out |= (decode_byte (*pt) >> (6 - l));
- mutt_decoder_push_one (dec, out);
+ bufi[k++] = out;
c++;
if (c == linelen)
break;
}
- mutt_decoder_pop_to_state (dec, s);
+ convert_to_state (cd, bufi, &k, s);
pt++;
}
}
- mutt_decoder_push (dec, NULL, 0, NULL);
- mutt_decoder_pop_to_state (dec, s);
+ convert_to_state (cd, bufi, &k, s);
+ convert_to_state (cd, 0, 0, s);
state_reset_prefix(s);
}
void mutt_decode_attachment (BODY *b, STATE *s)
{
- char *charset = mutt_get_parameter ("charset", b->parameter);
int istext = mutt_is_text_type (b->type, b->subtype);
- DECODER *dec;
+ iconv_t cd = (iconv_t)(-1);
if (istext && s->flags & M_CHARCONV)
- dec = mutt_open_decoder (charset, Charset);
- else
- dec = mutt_open_decoder (NULL, NULL);
+ {
+ char *charset = mutt_get_parameter ("charset", b->parameter);
+ if (charset)
+ cd = mutt_iconv_open (Charset, charset);
+ }
fseek (s->fpin, b->offset, 0);
switch (b->encoding)
{
case ENCQUOTEDPRINTABLE:
- mutt_decode_quoted (s, b, istext, dec);
+ mutt_decode_quoted (s, b, istext, cd);
break;
case ENCBASE64:
- mutt_decode_base64 (s, b, istext, dec);
+ mutt_decode_base64 (s, b, istext, cd);
break;
case ENCUUENCODED:
- mutt_decode_uuencoded (s, b, istext, dec);
+ mutt_decode_uuencoded (s, b, istext, cd);
break;
default:
- mutt_decode_xbit (s, b, istext, dec);
+ mutt_decode_xbit (s, b, istext, cd);
break;
}
- mutt_free_decoder (&dec);
+ if (cd != (iconv_t)(-1))
+ iconv_close (cd);
}
void mutt_body_handler (BODY *b, STATE *s)