Commit e8c60bf3 e8c60bf334d29e9bda45eb0e290429980958a3e9 by Sergey Poznyakoff

Initial implementation of rfc2047_decode. Based on input from Kidong Lee <brian@ahmlhs.com>.

1 parent b2291f98
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Library Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GNU Mailutils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <mailutils/stream.h>
#include <mailutils/filter.h>
#include <mailutils/errno.h>
int
rfc2047_decode (const char *tocode, const char *input, char **ptostr)
{
int status = 0;
char *tmpcopy, *fromstr;
char *start_position = NULL;
char *buffer;
size_t bufsize;
size_t bufpos;
if (!tocode || !input || !ptostr)
return EINVAL;
/* Prepare a temporary copy of the input string (strtok_r is
going to modify it. */
tmpcopy = strdup (input);
if (!tmpcopy)
return ENOMEM;
fromstr = tmpcopy;
/* Allocate the buffer. It is assumed that encoded string is always
longer than it's decoded variant, so it's safe to use its length
as the first estimate */
bufsize = strlen (fromstr) + 1;
buffer = malloc (bufsize);
if (buffer == NULL)
{
free (tmpcopy);
return ENOMEM;
}
bufpos = 0;
while (*fromstr)
{
char *fromcode = NULL;
char *encoding_type = NULL;
char *encoded_text = NULL;
stream_t filter = NULL;
stream_t in_stream = NULL;
char *pbuffer = NULL;
const char *filter_type = NULL;
size_t nbytes = 0, size;
char *sp = NULL;
char *end_position = NULL;
start_position = strstr (fromstr, "=?");
if (!start_position)
break;
/* Copy the unencoded part */
nbytes = start_position - fromstr;
if (bufpos + nbytes > bufsize) /* just in case */
{
status = MU_ERR_BAD_2047_INPUT;
break;
}
memcpy (buffer + bufpos, fromstr, nbytes);
bufpos += nbytes;
fromcode = strtok_r (start_position + 2, "?", &sp);
encoding_type = strtok_r (NULL, "?", &sp);
encoded_text = strtok_r (NULL, "?", &sp);
if (sp[0] != '=')
{
status = MU_ERR_BAD_2047_INPUT;
break;
}
if (fromcode == NULL || encoding_type == NULL || encoded_text == NULL)
{
status = MU_ERR_BAD_2047_INPUT;
break;
}
size = strlen (encoded_text);
switch (toupper (encoding_type[0]))
{
case 'B':
filter_type = "base64";
break;
case 'Q':
filter_type = "quoted-printable";
break;
default:
status = MU_ERR_BAD_2047_INPUT;
break;
}
if (status != 0)
break;
memory_stream_create (&in_stream, 0, 0);
stream_write (in_stream, encoded_text, size, 0, NULL);
filter_create (&filter, in_stream, filter_type, MU_FILTER_DECODE,
MU_STREAM_READ);
while (stream_read (filter, buffer + bufpos, bufsize - bufpos, 0,
&nbytes) == 0 && nbytes)
{
/* FIXME: Need to convert character set */
bufpos += nbytes;
}
stream_close (filter);
stream_destroy (&filter, stream_get_owner (filter));
fromstr = sp + 1;
}
if (*fromstr)
{
size_t len = strlen (fromstr);
if (bufpos + len + 1 > bufsize) /* just in case */
status = MU_ERR_BAD_2047_INPUT;
else
{
memcpy (buffer + bufpos, fromstr, strlen (fromstr));
bufpos += strlen (fromstr);
}
}
buffer[bufpos++] = 0;
free (tmpcopy);
*ptostr = realloc (buffer, bufpos);
return status;
}