/*
* MIME-part-2 header 8-bit coding to MIME-coded-tokens
*
* Matti Aarnio <mea@nic.funet.fi> (copyright) 1992-1996, 2000,
* 2002-2003
*
* (and Markku T Jarvinen <mta@sci.fi>)
*/
#include "hostenv.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "ta.h"
#include "sysprotos.h"
/* extern FILE *vlog; */
#ifndef __
# ifdef __STDC__
# define __(x) x
# else
# define __(x) ()
# endif
#endif
extern void *emalloc();
extern void *erealloc();
/* #define DEFCHARSET "UNKNOWN-8BIT" */
int cvtspace_copy __((struct rcpt *rp));
#if 0
#define USE_NEW_MIME2_CODE /* TESTING! */ /* apparenly not yet ready.. */
#endif
#ifdef USE_NEW_MIME2_CODE
/*
* The header8bit2QP() -code is by Markku T. Jarvinen <mta@sci.fi>
* who made it for sendmail 8.7 (which lacks MIME-part-2)
*/
const char *Base16Code = "0123456789ABCDEF";
#define MINWORDLEN 4
#define MAXENCODEDLINE 75
#define MAXLINE 4096
#ifndef MAX
# define MAX(i1,i2) ((i1 < i2) ? i2 : i1)
#endif
static int
header8bit2QPnextword(line, word, len, inside, start_encode, fold, hdr_offset)
unsigned char **line;
unsigned char *word;
int *len;
int *inside;
unsigned char *start_encode;
int fold;
int hdr_offset;
{
int wordlen = 0, has8bit = (*inside), eightbitchars = 0;
unsigned char c, *tmp;
eightbitchars = strlen(start_encode)+2;
while ((!isspace(c = *(*line+wordlen)) && c != '\0' && c != '\n'
&& !(!fold && (c == '(' || c == ')')))
&& wordlen+(*len)+has8bit*(eightbitchars) < MAXENCODEDLINE) {
if (c > 127)
has8bit = 1;
if (c > 127 || c == '_' || c == '?' || c == '=' || c < 32)
eightbitchars += 2;
wordlen++;
}
if (wordlen &&
wordlen+(*len)+has8bit*(eightbitchars) >= MAXENCODEDLINE) {
has8bit = 1;
wordlen--;
c = *(*line+wordlen);
if (c > 127 || c == '_' || c == '?' || c == '=' || c < 32)
eightbitchars -= 2;
while (wordlen+(*len)+has8bit*(eightbitchars) >= MAXENCODEDLINE) {
wordlen--;
c = *(*line+wordlen);
if (c > 127 || c == '_' || c == '?' || c == '=' || c < 32)
eightbitchars -= 2;
}
if (wordlen < MINWORDLEN) {
(*len) = hdr_offset;
if (fold)
strcpy(word, "\n "); /* next line */
else
strcpy(word, " "); /* next word */
return 1;
}
(*inside) = 1; /* need to split line, so continue inside */
} else {
(*inside) = 0; /* true word boundary */
}
tmp = word;
if (has8bit) {
strcpy(word, start_encode);
tmp += strlen(start_encode);
(*len) += strlen(start_encode);
}
while (wordlen) {
if (has8bit &&
(**line>127 || **line=='?' || **line=='_' || **line<32)) {
*tmp++ = '=';
*tmp++ = Base16Code[(**line >> 4) & 0x0f];
*tmp++ = Base16Code[**line & 0x0f];
(*len) += 3;
} else {
*tmp++ = **line;
(*len)++;
}
(*line)++;
wordlen--;
}
if (has8bit) {
*tmp++ = '?';
*tmp++ = '=';
(*len) += 2;
}
if ((*inside)==0) {
*tmp++ = (**line);
(*len)++;
(*line)++;
}
*tmp = '\0';
return 0;
}
/*
* go the line word by word and return the result
* line will be split on whitespace if possible
*/
static int
header8bit2QP(vlog, line, defcharset, outp, sizep, osizep, fold)
FILE *vlog;
unsigned char *line;
const char *defcharset;
unsigned char **outp;
int *sizep, *osizep;
int fold;
{
unsigned char *ptr, *outptr, *outline;
unsigned char tmp[MAX(MAXLINE,BUFSIZ)];
unsigned char word[MAXENCODEDLINE+2];
int len=0, abslen=0, lines=0, linelen=0, inside=0, hdr_offset=1;
int fffppp;
linelen = strlen(line);
ptr = line;
if (vlog)
fprintf(vlog,"header8bit2QP: QP\n");
sprintf((void*)tmp, "=?%s?Q?", defcharset);
#ifndef TRUSTFORMAT
while (*ptr != '\0' && *ptr != ':') {
ptr++;
hdr_offset++;
}
if (*ptr == '\0')
hdr_offset = 1;
else
hdr_offset++;
ptr = line;
#endif
while (*ptr != '\0' && lines == 0) {
int wlen;
if (header8bit2QPnextword(&ptr, word, &len, &inside, tmp, fold, hdr_offset)) {
lines++;
}
wlen = strlen(word);
abslen += wlen;
if (abslen >= *sizep) {
*outp = erealloc(*outp,abslen+2);
*sizep = abslen+2;
}
memcpy(*outp+*osizep, word, wlen+1);
*osizep += wlen;
}
#if 0
{
int fffppp = open("/tmp/ss", 256+8+1, 0777);
write(fffppp, line, strlen(line));
write(fffppp, out, strlen(out));
close(fffppp);
}
#endif
return 1;
}
#endif
/* This is rather half-baked approach, it creates correct tokens,
but if two tokens wind up adjacent, or one's length exceeds
recommended maximum, or ... then things aren't perfect. */
int
headers_to_mime2(rp,defcharset,vlog)
struct rcpt *rp;
const char *defcharset;
FILE *vlog;
{
#ifndef USE_NEW_MIME2_CODE
char **inhdr;
/* int wasmime2word = 0; */
if (*(rp->newmsgheadercvt) == NULL)
if (!cvtspace_copy(rp))
return -1; /* Failed to copy ! */
inhdr = *(rp->newmsgheadercvt);
while (inhdr && *inhdr) {
char *hdr = *inhdr;
char *s, *p, *q, s0;
int len = 0;
char *newbuf = NULL;
int toklen;
int column;
qphdr_restart:
column = 0;
for (s = (char*)hdr; *s; ++s) {
int c = (*s) & 0xFF;
++column;
if (c == '\n') column = 0;
if (c != '\n' && c != '\t' && (c < ' ' || c > 126)) {
/* Bad stuff, can't exist in the headers! */
if (vlog) fprintf(vlog,"8-bit header: '%s'\n",hdr);
/* Now rewind BACK to begin of this token,
separators are: '\n', ' ','\t','(' */
while (s > (char*)hdr && *s != ' ' && *s != '\n' &&
*s != '\t' && *s != '(' && *s != ')')
--s, --column;
if (column < 1) column = 1; /* just for safety.. */
s0 = *s;
if (s > (char*)hdr) ++s;
/* Now the 's' points at the begin of the token */
p = (char*)hdr;
if (!newbuf) {
len = strlen(s)*3; /* If it ALL turns into QP */
len += ((s - hdr)
+ 20 + strlen(defcharset)); /* Slag at the length */
newbuf = (char*)emalloc(len);
}
/* Copy the head */
q = newbuf;
while (p < s) *q++ = *p++;
sprintf(q," =?%s?Q?", defcharset);
toklen = 0;
q += strlen(q);
if (s0 == ' '|| s0 == '\t' || s0 == '\n') {
strcpy(q, "=20");
q += 3;
}
#define TOKENCUTEXPR(c) (c != ' ' && c != '\t' && c != ')' && c != '\n')
for ( ; *s && TOKENCUTEXPR(*s); ++s, ++toklen) {
if (toklen > 15 || (column > 76 && toklen > 0)) {
/* Arbitrary maximum token length,
possibly too long header, wanting to
wrap... */
toklen = q - newbuf;
len += 15+strlen(defcharset);
newbuf = realloc(newbuf, len);
q = newbuf + toklen;
strcpy(q,"?="); q += 2;
column += 2;
if (column+strlen(defcharset) > 76-8) {
strcpy(q, "\n\t"); q += 2;
column = 1;
} else {
strcpy(q, " "); q += 1;
++column;
}
sprintf(q,"=?%s?Q?", defcharset);
column += strlen(q);
q += strlen(q);
toklen = 0;
}
c = (*s) & 0xFF;
if (c < ' ' || c > 126 || c == '"' ||
c == '=' || c == '?' || c == '_') {
sprintf(q, "=%02X", c);
q += 3;
column += 3;
} else {
*q++ = c;
++column;
}
}
/* now we ignore column, as we restart the processor
after copying the old tail into place. */
strcpy(q,"?="); q += 2;
strcpy(q,(void*)s);
if(vlog)fprintf(vlog,"After processing: '%s'\n",newbuf);
ctlfree(rp->desc,*inhdr);
hdr = *inhdr = newbuf;
newbuf = NULL;
goto qphdr_restart;
} else {
}
}
if (newbuf) free(newbuf);
++inhdr;
}
return 0;
#else /* USE_NEW_MIME2_CODE */
/* New MIME-2 code by mta@sci.fi in use.. */
char **inhdr, **inhdr1;
char **outhdr, *s, **oh;
int outcnt = 0;
char *sumstr = emalloc(1);
int sumlen = 0;
*sumstr = 0;
outhdr = NULL;
if (*(rp->newmsgheadercvt) == NULL)
if (!cvtspace_copy(rp))
return -1; /* Failed to copy ! */
inhdr = *(rp->newmsgheadercvt);
inhdr1 = inhdr;
while (inhdr && *inhdr) {
int thislen = strlen(*inhdr);
if (**inhdr == ' ' || **inhdr == '\t') {
char *nn;
/* Continuation line.. */
nn = erealloc(sumstr,sumlen+thislen+2);
if (!nn) return -1; /* AUTCH! */
memcpy(nn+sumlen,*inhdr,thislen);
strcpy(nn+sumlen+thislen,"\n");
sumlen += thislen+1;
sumstr = nn;
} else {
/* Not a continuation line, Some sort of 'first line' */
if (sumlen > 0) {
char *s, *p;
int rc, size = sumlen;
char *outstr = emalloc(sumlen);
int osize = 0;
rc = header8bit2QP(vlog,sumstr,defcharset,&outstr,&size,&osize,1);
s = outstr;
if (outhdr == NULL)
outhdr = (char **)emalloc(sizeof(void*) * 2);
else
outhdr = (char**)erealloc(outhdr,
sizeof(void*) * (outcnt+2));
outhdr[outcnt] = (char*)emalloc(osize+1);
memcpy(outhdr[outcnt],s,osize+1);
++outcnt;
outhdr[outcnt] = NULL;
/* Clean up the results */
sumlen = 0;
free(outstr);
} /* sumlen > 0 */
/* Collect the 'first line' */
sumstr = erealloc(sumstr,thislen+2);
if (!sumstr) return -1; /* AUTCH! */
strcpy(sumstr,*inhdr);
strcpy(sumstr+thislen,"\n");
sumlen = thislen+1;
}
++inhdr;
}
/* Process the last of the headers */
if (sumlen > 0) {
char *s, *p;
int rc, size = sumlen;
char *outstr = emalloc(sumlen);
int osize = 0;
rc = header8bit2QP(vlog,sumstr,defcharset,&outstr,&size,&osize,1);
s = outstr;
size = strlen(s);
if (outhdr == NULL)
outhdr = (char **)emalloc(sizeof(void*) * 2);
else
outhdr = (char**)erealloc(outhdr,
sizeof(void*) * (outcnt+2));
outhdr[outcnt] = (char*)emalloc(size+1);
strcpy(outhdr[outcnt],s);
++outcnt;
outhdr[outcnt] = NULL;
/* Clean up the results */
sumlen = 0;
free(outstr);
} /* sumlen > 0 */
free(sumstr);
/* replace the converted headers with outhdr -set. */
inhdr = outhdr;
oh = NULL;
outcnt = 0;
while (*inhdr) {
char *s = *inhdr;
while (s && *s) {
char *p = strchr(s,'\n');
int len;
if (p) *p++ = 0;
len = strlen(s);
if (outcnt == 0)
oh = (char**)emalloc(sizeof(void*) * 2);
else
oh = (char**)erealloc(oh,sizeof(void*) * (outcnt+2));
/* -- copy -- */
oh[outcnt] = (char*)emalloc(len+1);
memcpy(oh[outcnt],s,len+1);
oh[++outcnt] = NULL;
/* -- Continuation line ? -- */
if (p) s = p;
else s = NULL;
}
free(*inhdr);
++inhdr;
}
free(outhdr);
inhdr1 = inhdr = *(rp->newmsgheadercvt);
*(rp->newmsgheadercvt) = oh;
while (*inhdr)
ctlfree(rp->desc,*inhdr++);
ctlfree(rp->desc,inhdr1);
return 0;
#endif /* USE_NEW_MIME2_CODE */
}
syntax highlighted by Code2HTML, v. 0.9.1