/*
 *	MIME-part-2 header 8-bit coding to MIME-coded-tokens
 *
 *      Matti Aarnio <mea@nic.funet.fi>  (copyright) 1992-1996
 *	(and   Markku T Jarvinen <mta@sci.fi>)
 */

#include "hostenv.h"
#include <varargs.h>
#include <stdio.h>
#include <sys/types.h>
#include "ta.h"
#include "sysprotos.h"

extern FILE *verboselog;

#ifndef	__
# ifdef __STDC__
#  define __(x) x
# else
#  define __(x) ()
# endif
#endif


extern void *emalloc();
extern void *realloc();

int cvtspace_copy __((struct rcpt *rp));

/* #define USE_NEW_MIME2_CODE /* TESTING! */ /* not yet ready.. */
#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+(*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(line, defcharset, outp, sizep, fold)
     unsigned char *line;
     const char *defcharset;
     unsigned char **outp;
     int *sizep;
     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 (verboselog)
	  fprintf(verboselog,"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') {
	  if (header8bit2QPnextword(&ptr, word, &len, &inside, tmp, fold, hdr_offset)) {
	    lines++;
	  }
	  abslen += strlen(word);
	  if (abslen >= *sizep) {
	    *outp = realloc(*outp,abslen+2);
	    *sizep = abslen+2;
	  }
	  strcat(*outp, word);
	}
#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,verboselog)
	struct rcpt *rp;
	FILE *verboselog;
{
#ifndef USE_NEW_MIME2_CODE
	char **inhdr;

	if (*(rp->newmsgheadercvt) == NULL)
	  if (!cvtspace_copy(rp))
	    return -1;	/* Failed to copy ! */

	inhdr = *(rp->newmsgheadercvt);

	while (inhdr && *inhdr) {
	  char *hdr = *inhdr;
	  u_char *s, *p, *q;
	  int len;
	  u_char *newbuf = NULL;

      qphdr_restart:

	  for (s = (u_char*)hdr; *s; ++s) {
	    if (*s != '\t' && (*s < ' ' || *s > 126)) {

	      /* Bad stuff, can't exist in the headers! */
if (verboselog) fprintf(verboselog,"8-bit header: '%s'\n",hdr);

	      /* Now rewind BACK to begin of this token,
		 separators are: ' ','\t','(' */
	      while (s > (u_char*)hdr && *s != ' ' &&
		     *s != '\t' && *s != '(' && *s != ')')
		--s;
	      if (*s == ' ' || *s == '\t' || *s == ')') ++s;
	      /* Now the 's' points at the begin of the token */
	      p = (u_char*)hdr;
	      if (!newbuf) {
		len = strlen(s)*3; /* If it ALL turns into QP */
		len += ((char*)s - hdr) + 30; /* Slag at the length */
		newbuf = (u_char*)emalloc(len);
	      }
	      /* Copy the head */
	      q = newbuf;
	      while (p < s) *q++ = *p++;
	      strcpy(q,"=?UNKNOWN-8BIT?Q?");
	      q += 17; /* 17 chars above */

	      for ( ; *s && (*s != ' ' && *s != '\t' && *s != ')'); ++s) {
		if (*s < ' '  || *s > 126  ||
		    *s == '=' || *s == '?' || *s == '_') {
		  sprintf((void*)q,"=%02X",*s);
		  q += 3;
		} else
		  *q++ = *s;
	      }
	      strcpy(q,"?="); q += 2;
	      strcpy(q,s);
if(verboselog)fprintf(verboselog,"After processing: '%s'\n",newbuf);
	      ctlfree(rp->desc,*inhdr);
	      hdr = *inhdr = (char *)newbuf;
	      newbuf = NULL;
	      goto qphdr_restart;
	    }
	  }
	  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;
	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) {
	  char *nn;
	  int thislen = strlen(*inhdr);

	  if (**inhdr == ' ' || **inhdr == '\t') {
	    /* Continuation line.. */
	    nn = realloc(sumstr,sumlen+thislen+2);
	    if (!nn) return -1; /* AUTCH! */
	    strcat(nn+sumlen,*inhdr);
	    strcat(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 = 0;
	      char *outstr = emalloc(sumlen);

	      rc = header8bit2QP(sumstr,DEFCHARSET,&outstr,&size,1);
	      s = outstr;
	      while (s && *s) {
		p = strlen(s,'\n');
		if (p) *p++ = 0;
		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;
		s = p;
	      }

	      /* Clean up the results */
	      sumlen = 0;
	      free(outstr);
	    } /* sumlen > 0 */

	    /* Collect the 'first line' */
	    nn = realloc(sumstr,thislen+2);
	    if (!nn) return -1; /* AUTCH! */
	    strcpy(sumstr,*inhdr);
	    sumlen = thislen;

	  }
	}

	/* Process the last of the headers */

	if (sumlen > 0) {
	  char *s, *p;
	  int rc, size = 0;
	  char *outstr = emalloc(sumlen);

	  rc = header8bit2QP(sumstr,DEFCHARSET,&outstr,&size,1);
	  s = outstr;
	  while (s && *s) {
	    p = strlen(s,'\n');
	    if (p) *p++ = 0;
	    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;
	    s = p;
	  }

	  /* Clean up the results */
	  sumlen = 0;
	  free(outstr);
	} /* sumlen > 0 */
	free(sumstr);

	/* XX: replace the converted headers with  outhdr -set. */
	    /* XX: resize (enlarge) the header array if need be */	

#endif /* USE_NEW_MIME2_CODE */
}
