static char rcsid[] = "@(#)$Id: hdrdecode.c,v 1.22 2006/07/01 07:37:48 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.22 $ $State: Exp $
*
* Author: Kari Hurtta <hurtta+elm@posti.FMI.FI> (was hurtta+elm@ozone.FMI.FI)
*
* Partially based on mime_decode.c, which is initially
* written by: Michael Elkins <elkins@aero.org>, 1995
*****************************************************************************/
#include "headers.h"
#include "s_me.h"
DEBUG_VAR(Debug,__FILE__,"mime");
int index_hex[128] = {
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1,
-1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
};
int index_64[128] = {
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
-1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
};
char * blstrpbrk (string, set)
char *string;
CONST char *set;
{
char *p;
for (p = string; *p; p++)
if ('\\' == *p) {
p++;
if ('\0' == *p)
return NULL;
} else if (NULL != strchr(set,*p))
return p;
return NULL;
}
void append_string(res,s)
struct string ** res;
CONST struct string *s;
{
if (!*res)
*res = dup_string(s);
else {
struct string *t = cat_strings(*res,s,1);
free_string(res);
*res = t;
}
}
static unsigned char * us_str P_((char *str));
static unsigned char * us_str(str)
char *str;
{
return (unsigned char *)str;
}
static char *us2s P_((unsigned char *str));
static char *us2s(str)
unsigned char *str;
{
return (char *)str;
}
static struct string * hdr_qp_decode P_((charset_t set,char *buffer,
char *lang));
static struct string * hdr_qp_decode(set,buffer,lang)
charset_t set;
char *buffer;
char *lang;
{
struct string *ret = lang ? new_langstring(set,lang) : new_string(set);
unsigned char *p;
for (p = us_str(buffer); *p; p++) {
switch(*p) {
int a,b;
case '_':
add_streambyte_to_string(ret,' ');
break;
case '=':
p++;
if (!*p)
goto fail;
if ((a = hex(*p)) < 0)
goto fail;
p++;
if (!*p)
goto fail;
if ((b = hex(*p)) < 0)
goto fail;
add_streambyte_to_string(ret,a*16+b);
break;
default:
add_streambyte_to_string(ret,*p);
break;
}
}
return ret;
fail:
DPRINT(Debug,20,(&Debug,
"hdr_qp_decode: FAIL: buffer=%s, next char=%c\n",
buffer,*p));
free_string(&ret);
return NULL;
}
static struct string * hdr_base64_decode P_((charset_t set,char *buffer,
char *lang));
static struct string * hdr_base64_decode(set,buffer,lang)
charset_t set;
char *buffer;
char *lang;
{
struct string *ret = lang ? new_langstring(set,lang) : new_string(set);
int val = 0;
int bits = 0;
unsigned char *p;
for (p = us_str(buffer); *p; p++) {
int a;
if ('=' == *p)
break;
if ((a=base64(*p)) < 0)
goto fail;
val = (val << 6) | a;
bits += 6;
if (bits >= 8) {
int n;
n = val >> (bits-8);
val -= n << (bits-8);
bits -= 8;
add_streambyte_to_string(ret,n);
}
}
return ret;
fail:
DPRINT(Debug,20,(&Debug,
"hdr_base64_decode: FAIL: buffer=%s, next char=%c\n",
buffer,*p));
free_string(&ret);
return NULL;
}
static struct string * hdr_decode_word P_((char *buffer));
static struct string * hdr_decode_word(buffer)
char *buffer;
{
char * temp = safe_strdup(buffer);
char *p = temp;
char *sn = NULL;
char *lang = NULL;
char E = '\0';
char *encoded = NULL;
struct string *ret = NULL;
charset_t set;
char *front, *end;
struct string *fstr, *estr;
/* Pasear: front, end are used to solve buffer: abc""=?...?=" problem */
front = p;
while (*p && '=' != *p) ++p;
if (front != p && '=' == *p && '"' == *(p-1)) *(p-1) = '\0';
if ('=' != *p)
goto fail;
*p = '\0'; ++p;
if ('?' != *p++)
goto fail;
sn = p;
while (*p && '?' != *p && '*' != *p)
p++;
if (!*p)
goto fail;
if ('*' == *p) {
*p++ = '\0';
lang = p;
while (*p && '?' != *p && '*' != *p)
p++;
if ('?' != *p)
goto fail;
}
*p++ = '\0';
E = *p++;
if ('Q' != E && 'B' != E &&
'q' != E && 'b' != E)
goto fail;
if ('?' != *p++)
goto fail;
encoded = p;
while (*p && '?' != *p)
p++;
if (!*p)
goto fail;
*p = '\0';
p++;
if ('=' != *p++)
goto fail;
if ('"' == *p) ++p;
end = p;
set = MIME_name_to_charset(sn,CHARSET_create);
switch(E) {
case 'Q':
case 'q':
ret = hdr_qp_decode(set,encoded,lang);
break;
case 'B':
case 'b':
ret = hdr_base64_decode(set,encoded,lang);
break;
}
/* Pasear */
if (ret){
estr = ret;
fstr = new_string2(system_charset,us_str(front));
fstr = ret = cat_strings(fstr, ret, 0);
free_string(&estr);
estr = new_string2(system_charset,us_str(end));
ret = cat_strings(ret, estr, 0);
free_string(&estr);
free_string(&fstr);
}
fail:
if (!ret) {
DPRINT(Debug,20,(&Debug,
"hdr_decode_word: FAIL: buffer='%s' -- next char=%c\n",
buffer,*p));
}
free(temp);
return ret;
}
static struct string * hdr_dequote P_((char *buffer,
charset_t defcharset));
static struct string * hdr_dequote(buffer,defcharset)
char *buffer;
charset_t defcharset;
{
struct string * ret;
char *p;
char *t = buffer;
for (p = buffer; *p; p++) {
if ('\\' == *p) {
p++;
if ('\0' == *p)
break;
} else if ('"' == *p)
continue;
*t++ = *p;
}
*t = '\0';
ret = new_string2(defcharset,us_str(buffer));
return ret;
}
static struct string * hdr_comment P_((char *buffer,
charset_t defcharset,
int demime));
static struct string * hdr_comment(buffer,defcharset,demime)
char *buffer;
charset_t defcharset;
int demime;
{
struct string * ret = new_string(defcharset);
char * walk, *ptr;
unsigned char last_char = 0;
for (ptr = buffer; ptr && *ptr; ptr = walk) {
unsigned char safe = 0;
struct string * ok = NULL;
int nostore = 0;
walk = blstrpbrk(ptr," \t\r\n()");
if (walk) {
safe = *walk;
*walk = '\0';
walk++;
}
/* Try decode it (perhaps not encoded word at all) */
ok = hdr_decode_word(ptr);
if (!ok) {
/* now if it was not encoded, then we need add last space */
if (last_char) {
unsigned char ascii[2];
ascii[0] = last_char;
ascii[1] = '\0';
add_ascii_to_string(ret,ascii);
}
/* If decoding failed add word as is */
ok = new_string2(defcharset,us_str(ptr));
nostore = 1;
} else if (last_char == ')' || last_char == '(') {
/* Also we need add last char if not space */
add_streambyte_to_string(ret,last_char);
}
/* Now compine strings */
append_string(&ret,ok);
free_string(&ok);
if (nostore) {
/* If last was not encoded we are not going to delete
space between words
*/
if (safe) {
unsigned char ascii[2];
ascii[0] = safe;
ascii[1] = '\0';
add_ascii_to_string(ret,ascii);
}
last_char = 0;
} else
last_char = safe;
}
return ret;
}
static struct string * hdr_phrase P_((char *buffer,
charset_t defcharset,
int demime));
static struct string * hdr_phrase(buffer,defcharset,demime)
char *buffer;
charset_t defcharset;
int demime;
{
struct string * ret = new_string(defcharset);
char **tokenized = rfc822_tokenize(buffer);
unsigned char * last_char = NULL;
int i, encoded;
char* p;
for (i = 0; tokenized[i]; i++) {
struct string * ok = NULL;
int nostore = 0;
/* Pasear: detect if it is a encoded string */
encoded = 0;
if ('"' == tokenized[i][0]){
p = tokenized[i];
while (*p && *p != '=') ++p;
if (*p && *p == '=' && *(p+1) && *(p+1) == '?' )
encoded = 1;
}
if ('(' == tokenized[i][0]) {
/* we need add last space */
if (last_char)
add_ascii_to_string(ret,last_char);
ok = hdr_comment(tokenized[i],defcharset,demime);
nostore = 1;
} else if (!encoded && '"' == tokenized[i][0]) {
/* we need add last space */
if (last_char)
add_ascii_to_string(ret,last_char);
ok = hdr_dequote(tokenized[i],defcharset);
nostore = 1;
} else {
/* Try decode it (perhaps not encoded word at all) */
if (demime)
ok = hdr_decode_word(tokenized[i]);
if (!ok) {
/* now if it was not encoded, then we need add last space */
if (last_char)
add_ascii_to_string(ret,last_char);
/* If decoding failed add word as is */
ok = new_string2(defcharset,us_str(tokenized[i]));
nostore = 1;
}
}
/* Now compine strings */
append_string(&ret,ok);
free_string(&ok);
last_char = 0;
if (!nostore && tokenized[i+1] &&
(' ' == tokenized[i+1][0] ||
'\t' == tokenized[i+1][0] ||
'\r' == tokenized[i+1][0] ||
'\n' == tokenized[i+1][0])) {
i++;
last_char = us_str(tokenized[i]);
}
}
free_rfc822tokenized(tokenized);
return ret;
}
static struct string * hdr_text P_((char *buffer,
charset_t defcharset,
int demime));
static struct string * hdr_text(buffer,defcharset,demime)
char *buffer;
charset_t defcharset;
int demime;
{
struct string * ret = NULL;
char * walk, *ptr;
unsigned char * last_space = NULL;
for (ptr = buffer; ptr && *ptr; ptr = walk) {
unsigned char safe = 0;
struct string * ok = NULL;
int nostore = 0;
char * skipstore = NULL;
walk = strpbrk(ptr," \t\r\n");
if (walk) {
safe = *walk;
*walk = '\0';
walk++;
skipstore = walk;
/* Jump to next word */
while (*walk &&
NULL != strchr(" \t\r\n", *walk))
walk++;
}
/* Try decode it (perhaps not encoded word at all) */
if (demime)
ok = hdr_decode_word(ptr);
if (!ok) {
/* now if it was not encoded, then we need add last space */
if (last_space) {
if (!ret)
ret = new_string(defcharset);
add_ascii_to_string(ret,last_space);
}
/* If decoding failed add word as is */
ok = new_string2(defcharset,us_str(ptr));
nostore = 1;
}
/* Now compine strings */
append_string(&ret,ok);
free_string(&ok);
if (last_space)
free(last_space);
last_space = NULL;
if (safe) {
int L;
if (!skipstore)
panic("STRING PANIC",__FILE__,__LINE__,"hdr_text",
"skipstore not set",0);
L = walk - skipstore;
if (L < 0)
panic("STRING PANIC",__FILE__,__LINE__,"hdr_text",
"bad len",0);
last_space = safe_malloc(L+2);
last_space[0] = safe;
if (L > 0)
strncpy(us2s(last_space)+1,skipstore,L);
last_space[L+1] = '\0';
}
if (nostore) {
/* If last was not encoded we are not going to delete
space between words
*/
if (last_space) {
if (!ret)
ret = new_string(defcharset);
add_ascii_to_string(ret,last_space);
free(last_space);
last_space = NULL;
}
}
}
return ret;
}
/* class is one of HDR_PHRASE, HDR_COMMENT, HDR_TEXT */
struct string * hdr_to_string(class,buffer,defcharset, demime)
int class;
CONST char *buffer;
charset_t defcharset;
int demime;
{
struct string * ret = NULL;
char *temp = safe_strdup(buffer);
switch(class) {
case HDR_PHRASE:
ret = hdr_phrase(temp,defcharset,demime);
break;
case HDR_COMMENT:
ret = hdr_comment(temp,defcharset,demime);
break;
case HDR_TEXT:
ret = hdr_text(temp,defcharset,demime);
break;
}
free(temp);
if (!ret) {
ret = new_string(defcharset);
DPRINT(Debug,30,(&Debug,
"hdr_to_string: Returning empty header...\n"));
}
DPRINT(Debug,30,(&Debug,
"hdr_to_string=%p (class=%d, buffer='%s', defcharset=%p '%s', demime=%d)\n",
ret,
class,buffer,
defcharset,
defcharset->MIME_name ? defcharset->MIME_name : "<none>",
demime));
return ret;
}
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1