/*
* $Id$
* Changes made to the original by Olafur Osvaldsson (See ChangeLog)
* Copyright (C) 2002 Olafur Osvaldsson
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
** Copyright 1998 - 2000 Double Precision, Inc. See COPYING for
** distribution information.
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#if defined(DEBUG) && defined(DMALLOC)
#include <dmalloc.h>
#endif /* DEBUG */
static const char rcsid[] = "$Id$";
static const char xdigit[] = "0123456789ABCDEF";
static char *
rfc2047_search_quote(const char **ptr)
{
const char *p = *ptr;
char *s;
while (**ptr && **ptr != '?')
++* ptr;
if ((s = malloc(*ptr - p + 1)) == 0)
return (0);
memcpy(s, p, *ptr - p);
s[*ptr - p] = 0;
return (s);
}
static int
nyb(int c)
{
const char *p;
c = toupper((int)(unsigned char)c);
p = strchr(xdigit, c);
return (p ? p - xdigit : 0);
}
static unsigned char decode64tab[256];
static int decode64tab_init = 0;
static size_t
decodebase64(char *ptr, size_t cnt)
{
size_t i , j;
char a , b, c;
size_t k;
if (!decode64tab_init) {
for (i = 0; i < 256; i++)
decode64tab[i] = 0;
for (i = 0; i < 64; i++)
decode64tab[(int)
("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i])] = i;
decode64tab[(int)'='] = 99;
}
i = cnt / 4;
i = i * 4;
k = 0;
for (j = 0; j < i; j += 4) {
int w = decode64tab[(int)(unsigned char)ptr[j]];
int x = decode64tab[(int)(unsigned char)ptr[j + 1]];
int y = decode64tab[(int)(unsigned char)ptr[j + 2]];
int z = decode64tab[(int)(unsigned char)ptr[j + 3]];
a = (w << 2) | (x >> 4);
b = (x << 4) | (y >> 2);
c = (y << 6) | z;
ptr[k++] = a;
if (ptr[j + 2] != '=')
ptr[k++] = b;
if (ptr[j + 3] != '=')
ptr[k++] = c;
}
return (k);
}
/*
** This is the main rfc2047 decoding function. It receives rfc2047-encoded
** text, and a callback function. The callback function is repeatedly
** called, each time receiving a piece of decoded text. The decoded
** info includes a text fragment - string, string length arg - followed
** by the character set, followed by a context pointer that is received
** from the caller. If the callback function returns non-zero, rfc2047
** decoding terminates, returning the result code. Otherwise,
** rfc2047_decode returns 0 after a successfull decoding (-1 if malloc
** failed).
*/
int
rfc2047_decode(const char *text, int (*func) (const char *, int,
const char *, void *),
void *arg)
{
int rc;
int had_last_word = 0;
const char *p;
char *chset;
char *encoding;
char *enctext;
while (text && *text) {
if (text[0] != '=' || text[1] != '?') {
p = text;
while (*text) {
if (text[0] == '=' && text[1] == '?')
break;
if (!isspace((int)(unsigned char)*text))
had_last_word = 0;
++text;
}
if (text > p && !had_last_word) {
rc = (*func) (p, text - p, 0, arg);
if (rc)
return (rc);
}
continue;
}
text += 2;
if ((chset = rfc2047_search_quote(&text)) == 0)
return (-1);
if (*text)
++text;
if ((encoding = rfc2047_search_quote(&text)) == 0) {
free(chset);
return (-1);
}
if (*text)
++text;
if ((enctext = rfc2047_search_quote(&text)) == 0) {
free(encoding);
free(chset);
return (-1);
}
if (*text == '?' && text[1] == '=')
text += 2;
if (strcmp(encoding, "Q") == 0 || strcmp(encoding, "q") == 0) {
char *q, *r;
for (q = r = enctext; *q;) {
int c;
if (*q == '=' && q[1] && q[2]) {
*r++ = (char)(
nyb(q[1]) * 16 + nyb(q[2]));
q += 3;
continue;
}
c = *q++;
if (c == '_')
c = ' ';
*r++ = c;
}
*r = 0;
}
else if (strcmp(encoding, "B") == 0 || strcmp(encoding, "b") == 0) {
enctext[decodebase64(enctext, strlen(enctext))] = 0;
}
rc = (*func) (enctext, strlen(enctext), chset, arg);
free(enctext);
free(chset);
free(encoding);
if (rc)
return (rc);
had_last_word = 1; /* Ignore blanks between enc words */
}
return (0);
}
/*
** rfc2047_decode_simple just strips out the rfc2047 decoding, throwing away
** the character set. This is done by calling rfc2047_decode twice, once
** to count the number of characters in the decoded text, the second time to
** actually do it.
*/
struct simple_info {
char *string;
int index;
const char *mychset;
};
static int
count_simple(const char *txt, int len, const char *chset,
void *arg)
{
struct simple_info *iarg = (struct simple_info *)arg;
iarg->index += len;
return (0);
}
static int
save_simple(const char *txt, int len, const char *chset,
void *arg)
{
struct simple_info *iarg = (struct simple_info *)arg;
memcpy(iarg->string + iarg->index, txt, len);
iarg->index += len;
return (0);
}
char *
rfc2047_decode_simple(const char *text)
{
struct simple_info info;
info.index = 1;
if (rfc2047_decode(text, &count_simple, &info))
return (0);
if ((info.string = malloc(info.index)) == 0)
return (0);
info.index = 0;
if (rfc2047_decode(text, &save_simple, &info)) {
free(info.string);
return (0);
}
info.string[info.index] = 0;
return (info.string);
}
syntax highlighted by Code2HTML, v. 0.9.1