/*
 *
 * Copyright (C) 1993 Swedish University Network (SUNET)
 *
 *
 * This program is developed by UDAC, Uppsala University by commission
 * of the Swedish University Network (SUNET). 
 * 
 * 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 FITTNESS 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *
 *                                          Martin.Wendel@udac.uu.se
 *
 *                                          Martin Wendel
 *                                          UDAC	
 *                                          Box 174
 *                                          S-751 04 Uppsala
 *                                          Sweden
 */






#include "mk.h"
int ccc = 0;


/* 
**
** These functions are used to convert to or from some message encoding formats.
**
** They should change the following parameters:
**
**	buf->out		The output buffer
**	buf->inpos		Position where process of mp->in stopped
**	buf->outlen		Length of data in output buffer
**	buf->inrest		Backup buffer
**	buf->inrestlen		length of data in backup buffer
**	
**
**
**
*/



/* fromquotedp(mk, buf)
 **
 ** 	Converts a string , encoded with Quoted-Printable format, to a plain 
 **	octet character string.
 */

int
  fromquotedp(mk, buf)
MessageStruct *mk;
BufStruct *buf;
{
  MessageStruct *mkr;
  char *mkin;
  char *mkout;
  char *p;
  char hc[3];
  int cc;
  int result = 0;
  mkr = MkMess_Root;
  buf->inpos = 0;
  /* Init */
  if (!mk_init(mk, buf, &mkin, &mkout))
    return(result);

  /* remove tailing whitespace, they're not trusted */
  buf->inlen -= clearend(mkin);

  if (mk->investigate)
    {
      if (mkr->bound && !strncmp(mkr->bound->name, mkin, mkr->bound->namelen)) 
	{
	  mk->last = TRUE;
	  mk->end_line = linecount - 1;
	  mk->totlen = buf->outpartlen;
	  return(DONE);
	}
      else
	if (mk->last)
	  mk->end_line = linecount;
    }	  

  /* find '=' */
  p = (char *)index(mkin, '=');
  if (p == NULL)
    {
      /* Not found, return input almost unchanged */
      if (*mkin)
	strcpy(mkout, mkin);
      else
	*mkout = '\0';
      strcat(mkout, "\n");
      buf->outlen = strlen(mkout);
      buf->outpartlen += buf->outlen;
      buf->inpos = buf->inlen;
      buf->inpartlen += buf->inpos;
      mk->lfs = count_lfs(buf->out);
      if (mk->last && mk->investigate)
	  mk->totlen = buf->outpartlen;
      return(result); 
      
    }

  for (; p != (char *) NULL; p = (char *)index(p, '='))
    {	
      *p++ = '\0';
      if (*mkin) 
	{
	  strcpy(mkout, mkin);
	  cc = strlen(mkin);
	  mkin += cc;
	  mkout += cc;
	  buf->inpos += cc + 1;
	  buf->inpartlen += cc + 1;
	  buf->outlen += cc;
	  buf->outpartlen += cc;
	  
	}
      if (*p == '\0') 
	/* Soft line break */
	{
	  mk->lfs = count_lfs(buf->out);
	  if (mk->last && mk->investigate)
	    mk->totlen = buf->outpartlen;
	  return(result);
	}
      
      strncpy(hc, p, 2);
      hc[2] = '\0';
      /* Be nice, if hexnumber is illegal assume it is OK as is */
      if ((hc[2] = (char)strtol(hc, (char **)NULL, 16)) != NULL)
	{
	  if (hc[2] != '\0') 
	    { 
	      buf->outlen++;
	      buf->outpartlen++;
	      *mkout++ = hc[2];
	    }
	  buf->inpos += 2;
	  buf->inpartlen += 2;
	  p += 2;
	  mkin = p;
	}
      else 
	{
	  mkin++;
	  buf->inpos++;
	  buf->inpartlen++;
#ifdef EMILDEBUG
	  Mk_Log(LOG_ERR, "Quoted-Printable: decode failure: illegal hexchar: %s",
		 hc);
#endif
	  result = -1;
	}
    }
  /* No more hexchars */
  strcpy(mkout, mkin);
  cc = strlen(mkin);
  buf->outlen += cc;
  buf->outpartlen += cc;
  buf->inpartlen += cc;
  buf->inpos = buf->inlen;
  strcat(mkout, "\n");
  buf->outlen++;
  buf->outpartlen++;
  mk->lfs = count_lfs(buf->out);
  if (mk->last && mk->investigate) {
    mk->totlen = buf->outpartlen;
    return(DONE);
  }
  else
    return(OK);
}



/* toquotedp(mk, buf)
 **
 ** 	Encodes an octet string to Quoted-Printable format. Input is trusted 
 **	to be correct.
 */

int
  toquotedp(mk, buf)
MessageStruct *mk;
BufStruct *buf;
{
  char *mkin;
  char *mkout;
  int cc;
  int result = 0;
  
  buf->inpos = 0;
  /* Init */
  if (!mk_init(mk, buf, &mkin, &mkout))
    return(result);

  cc = buf->outlen;

  while (buf->inpos < buf->inlen) 
    {
      if (*mkin == '\n')
	/* Use NL's where they come */
	{
	  *mkout++ = *mkin;
	  buf->outpartlen++;
	  buf->outlen++;
	  cc = 0;
	  mk->lfs++;
	}
      else /* *mkin != '\n' */
	{
	  if (cc > 60)
	    /* Make lines approx. 60 chars long */
	    {
	      *mkout++ = '='; /* Soft line break */
	      *mkout++ = '\n';
	      buf->outlen += 2;
	      buf->outpartlen += 2;
	      cc = 0;	
	      mk->lfs++;
	    }
	  cc++;
	  if ((*mkout = ISO_TO_QP[(unsigned char)*mkin]) == '\0')
	    {
	      *mkout++ = '=';
	      sprintf(mkout, "%.2X", (unsigned char)*mkin);
	      mkout += 2;
	      buf->outlen += 3;
	      buf->outpartlen += 3;
	      cc += 2;
	    } 
	  else
	    {
	      mkout++;
	      buf->outlen++;
	      buf->outpartlen++;
	    }
	}
      mkin++;
      buf->inpos++;
      buf->inpartlen++;
    }
  *mkout = '\0';
  mk->lfs = count_lfs(buf->out);
}


/* frombase64(mk, buf)
 **
 ** 	Decodes a string, which is encoded with the Base64 format,
 **	to a plain octet string.
 **
 */

int
  frombase64(mk, buf)
MessageStruct *mk;
BufStruct *buf;
{
  MessageStruct *mkr;
  int i, p;
  unsigned long ptmk = 0;
  char *mkin;
  char *mkout;
  char ctest;
  int plen;
  int result = 0;
  mkr = MkMess_Root;
  buf->inpos = 0;
  /* Init */
  if (!mk_init(mk, buf, &mkin, &mkout))
    return(result);

  if (mk->investigate)
    {
      if (mkr->bound && !strncmp(mkr->bound->name, mkin, mkr->bound->namelen)) 
	{
	  mk->last = TRUE;
	  mk->end_line = linecount - 1;
	  mk->totlen = buf->outpartlen;
	  return(DONE);
	}
      else
	if (mk->last)
	  mk->end_line = linecount;
    }	  

  /* Clear bufin from beginning and ending whitespaces, they're not used. */
  buf->inlen -= clearend(mkin);

  for (; isspace(*mkin); mkin++) {
    buf->inpos++;
    buf->inpartlen++;
  }
  
  plen = buf->inlen;
  
  /* Iterate on a base 4 */
  for (i = 0; i < plen; i += 4) 
    {
      /* Process the next four chars */
      for (p = 0; p < 4; p++) 
	{
	  if (*mkin == '=') 
	      break;
	  if (p)
	    ptmk = (ptmk << 6);
	  else
	    ptmk = 0;
	  
	  ptmk = ptmk | (63 & 
			(ctest =  BASE64_TO_8BIT[(unsigned char)*mkin]));
	  if (ctest == 0 && (*mkin != '=' && *mkin != 'A')) {
#ifdef EMILDEBUG
	    Mk_Log(LOG_ERR, "Base64: decode failure: illegal character: %c",
		   *mkin);
#endif
	    return(-2); /* Fatal format error */
	  }

	  mkin++;
	  buf->inpos++;
	  buf->inpartlen++;
	}
      six_to_eight(ptmk, mk, buf, p, 3, ENCBASE64);
    }

  if (i < plen)
    {
      buf->inrestlen = plen - i;
      bcopy(mkin, buf->inrest, buf->inrestlen);
    }
  else
    {
      *buf->inrest = '\0';
      buf->inrestlen = 0;
    }
  mk->lfs = count_lfs(buf->out);
  if (mk->fpart == NULL)
    mk->fpart = get_applefile_type;
  (mk->fpart)(mk, buf);
  if (mk->investigate) {
    mk->totlen += buf->outlen;
  }
  else
    return(OK);
}


/* 	tobase64(mk, buf)
** 	Convert an octet string to base64. Input is trusted to be correct.
*/

int
  tobase64(mk, buf)
MessageStruct *mk;
BufStruct *buf;
{
  unsigned long ptmk = 0;
  int count;
  int pad;
  char *mkin;
  char *mkout;
  int plen = 0;
  int result = 0;
  
  buf->inpos = 0;
  
  /* Init */
  if (!mk_init(mk, buf, &mkin, &mkout))
    return(result);

  for (plen = buf->inlen - buf->inpos; plen >=54;)
    {
      plen = 54;
      for (count = 0; plen > 0; mkin++, plen--)
	{
	  if (count)
	    ptmk = (ptmk << 8); /* Shift left */
	  else 
	    ptmk = 0; /* Clear bit buffer */
      
	  /* Insert 8bit character */
	  ptmk = ptmk | (255 & *mkin);
	  count++;
	  buf->inpos++;
	  buf->inpartlen++;
      
	  if (count == 3) /* Read three, convert to base64 */
	    {
	      eight_to_six(ptmk, mk, buf, count, BASE64, 72, ENCBASE64);
	      count = 0;
	    }
	}
      plen = buf->inlen - buf->inpos;
    }
  if (mk->last) /* Last input, force linefeed and pads */
    {
      bool last;
      if (buf->inpos < buf->inlen)
	{
	  for (count = 0; buf->inpos <= buf->inlen; mkin++)
	    {
	      last = (buf->inpos == buf->inlen);
	      if (!last)
		{
		  if (count)
		    ptmk = (ptmk << 8);
		  else
		    ptmk = 0;
		  count++;
		  ptmk = ptmk | (255 & *mkin);
		  buf->inpos++;
		  buf->inpartlen++;
		}
	      if (count == 3 || last) /* Read three or EOF, convert to base64 */
		{
		  if (last)
		    Mk_Log(LOG_DEBUG,"Last on count = %i", count);
		  eight_to_six(ptmk, mk, buf, count, BASE64, 72, ENCBASE64);
		  count = 0;
		}
	      if (last)
		break;
	    }
	  /* last should be true here */
	  if ((pad = buf->linelen % 4) != 0)
	    for (; pad < 4; pad++)
	      {
		*(buf->out + buf->outlen) = '=';
		buf->outlen++;
		buf->outpartlen++;
	      }
	  *(buf->out + buf->outlen) = '\n';
	  buf->outlen++;
	  buf->outpartlen++;
	  mk->lfs++;
	}
      else /* !buf->inpos < buf->inlen */
	if (buf->linelen)
	  {
	    *(buf->out + buf->outlen) = '\n';
	    mk->lfs++;
	    buf->outlen++;
	    buf->outpartlen++;
	  }
      *buf->inrest = '\0';
      buf->inrestlen = 0;
    }
  else /* !mk->last */
    {
      if ((plen = buf->inlen - buf->inpos))
	{
	  bcopy(mkin, buf->inrest, plen);
	  buf->inrestlen = plen;
	}
      else
	{
	  *buf->inrest = '\0';
	  buf->inrestlen = 0;
	}
    }
}


/*
** 	to7bit(mk, buf)
**	Convert a possibly octet string to a 7bit ASCII string. Uses
** 	a destructive conversion map defined in MkTcl.c
*/
int
to7bit(mk, buf)
     MessageStruct *mk;
BufStruct *buf;
{
  char *mkin;
  char *mkout;
  int result = 0;
  buf->inpos = 0;
  buf->outlen = 0;
  
  /* Init */
  if (!mk_init(mk, buf, &mkin, &mkout))
    return(result);

  for(; buf->inpos < buf->inlen; mkin++) 
    {
      buf->inpos++;
      buf->inpartlen++;
      if (*mkin < 0)
	*mkout++ = ISO_TO_7BIT[(unsigned char)*mkin];
      else
	*mkout++ = *mkin;
      buf->outlen++;
      buf->outpartlen++;
    }
  return(OK);
}


int
textcheck(mk, buf)
     MessageStruct *mk;
BufStruct *buf;
{
  if (mk->highchars += count_high_char(buf->in))
    {
      mk->enc = ENC8BIT;
    }
  return(OK);
}

/*
**	tocharset(mk, buf)
**	A frontend to strcnv().
*/

int
tocharset(mk, buf)
     MessageStruct *mk;
BufStruct *buf;
{
  char *mkin;
  char *mkout;
  int result = 0;

  buf->inpos = 0;
  
  /* Init */
  if (!mk_init(mk, buf, &mkin, &mkout))
    return(result);

  /* Null terminate input */
  if (*(buf->in + buf->inlen))
    *(buf->in + buf->inlen) = '\0';

  strncnv(mk->to_charset, mk->from_charset, (CHAR8U *)mkout,
	  (CHAR8U *)mkin, BUFSIZE);
  buf->inpos += strlen(mkin);
  buf->outlen += strlen(mkout);
  buf->inpartlen += buf->inpos;
  buf->outpartlen += buf->outlen;
  mk->lfs = count_lfs(mkout);
}


/*
**
**	frombinhex(mk, buf)
**	Convert from BinHex to 8bit.
*/


frombinhex(mk, buf)
     MessageStruct *mk;
BufStruct *buf;
{
  

  int i, p, n;
  int plen;
  unsigned long ptmk = 0;
  char *mkin;
  char *mkout;
  char ctest;
  bool first;

  /* Init */
  buf->inpos = 0;
  buf->outlen = 0;
  buf->outpos = 0;
  if (!mk_init(mk, buf, &mkin, &mkout))
    return(OK);

  if (*mkin == '(')
    if (!strncasecmp(mkin, "(This", 5))
      {
	buf->outlen = 0;
	return(OK);
      }

  if (!mk->binhex)
    mk->binhex = (BinHexStruct *)xalloc(sizeof(BinHexStruct));

  if (!mk->fpart)
    mk->fpart = get_binhex_namelen;

  first = FALSE;
  if (*mkin == ':')
    {
      mkin++;
      buf->inpos++;
      buf->inpartlen++;
      first = TRUE;
      mk->fpart = get_binhex_namelen;
      if (*mkin == '\0')
	return(OK);
    }
	

  
  /* Clear bufin from beginning and ending whitespaces, they're not trusted. */
  buf->inlen -= clearend(mkin);
  for (; isspace(*mkin); mkin++) {
    buf->inpos++;
    buf->inpartlen++;
  }
  if (!buf->inlen)
    return(OK);

  if (!first)
    if (index(mkin, ':'))
      {
	mk->last = TRUE;
	buf->inlen--;
	buf->inpartlen++;
      }

  plen = buf->inlen - buf->inpos;
  if (!mk->last)
    plen = plen - (plen % 4);
  
  /* Iterate on a base 4 */
  for (i = 0; i < plen || mk->last; i += 4) 
    {
      n = buf->inlen - buf->inpos;
      /* Process the next four chars */
      for (p = 0; p < ((n < 4) ? n : 4); p++) 
	{
	  if (*mkin == ':')
	    break;
	  if (p)
	    ptmk = (ptmk << 6);
	  else
	    ptmk = 0;
	  
	  ptmk = ptmk | (63 & 
			 (ctest = BinHex[(unsigned char)*mkin]));

	  if (ctest == 0 && *mkin != '!') {
#ifdef EMILDEBUG
	    Mk_Log(LOG_ERR, "BinHex: decode failure: illegal character: %c",
		   *mkin);
#endif
	    return(ERROR_FORMAT); /* Fatal format error */
	  }

	  mkin++;
	  buf->inpos++;
	  buf->inpartlen++;
	}
      six_to_eight(ptmk, mk, buf, p, 3, ENCBINHEX);

      if (*mkin == ':')
	{
	  mk->last = TRUE;
	  break;
	}
    }
  if (buf->inpos < buf->inlen)
    {
      bcopy(mkin, buf->inrest, buf->inlen - buf->inpos);
      buf->inrestlen = buf->inlen - buf->inpos;
    }
  else
    {
      *buf->inrest = '\0';
      buf->inrestlen = 0;
    }
  if (*mkin == ':') {
    mk->last = TRUE;
    if (mk->investigate)
      mk->totlen = buf->outpartlen;
  }

  buf->outpos = 0;
  buf->outdiff = 0;
  i = (mk->fpart)(mk, buf);
  if (i < 0)
    return(i);
    
  if (mk->last && i == OK) {
#ifdef EMILDEBUG
    Mk_Log(LOG_ERR, "BinHex: decode failure: extra characters at end");
#endif
    return(ERROR_LESS);
  }
  else
    return(i);
}




/* 	tobinhex(mk, buf)
** 	Convert an octet string to BinHex. Input is trusted to be correct.
*/

int
  tobinhex(mk, buf)
MessageStruct *mk;
BufStruct *buf;
{
  unsigned long ptmk = 0;
  int count;
  char *mkin;
  char *mkout;
  int plen;
  int tohere;
  int result = 0;
  bool writerun = FALSE;

  if (!mk->binhex)
    mk->binhex = (BinHexStruct *)xalloc(sizeof(BinHexStruct));

  /* Add Empty Resource Fork if end of data */
  if (mk->last)
    tobinhexlast(mk, buf);

  if (mk->first)
    tobinhexfirst(mk, buf);

  /* Init */
  if (!mk_init(mk, buf, &mkin, &mkout))
    return(result);

  tohere = buf->inlen - (buf->inlen % 3);
  plen = buf->inlen - buf->inpos;

  for (count = 0; buf->inpos < tohere || mk->last; mkin++)
    {
      if (mk->binhex->run) {
	mkin--;
	*mkin = '\0';
	writerun= TRUE;
      }
      else
	mk->binhex->checksum = calc_crc(mk->binhex->checksum,
					(unsigned char) *mkin);

      if (count) 
	ptmk = (ptmk << 8); /* Shift left */
      else 
	ptmk = 0; /* Clear bit buffer */

      if (!mk->binhex->run) {
	if (plen > 0)
	  {
/* SKIT */
	    /* Insert 8bit character */
	    ptmk = ptmk | (255 & *mkin);
	    count++;
	    buf->inpos++;
	    plen--;
	    buf->inpartlen++;
	  }
      }
      else {
	mk->binhex->run = FALSE;
	ccc++;
	count++;
	tohere--;
      }
      if (0x90 == (unsigned char )*mkin) {
	mk->binhex->run = TRUE;
      }

      if (count == 3 || !plen)
	/* Written three, convert to base64 */
	{
	  if (count == 1 && (mk->binhex->run || writerun)) {
	    writerun = FALSE;
	  }
	  eight_to_six(ptmk, mk, buf, count, ToBinHex, 64, ENCBINHEX);
	  count = 0;
	}
      if (!plen)
	break;
    }
  if (mk->last) 
    {
      *(buf->out + buf->outlen) = ':';
      buf->outlen++;
      buf->outpartlen++;
      *(buf->out + buf->outlen) = '\n';
      buf->outlen++;
      buf->outpartlen++;
      *(buf->out + buf->outlen) = '\0';
      *buf->inrest = '\0';
      buf->inrestlen = 0;
    }
  else /* !mk->last */
    if (count = buf->inlen - tohere)
      {
	bcopy(mkin, buf->inrest, count);
	buf->inrestlen = count;
      }
    else
      {
	*buf->inrest = '\0';
	buf->inrestlen = 0;
      }
}


int
  tobinhexlast(mk, buf)
MessageStruct *mk;
BufStruct *buf;
{
  char *mkin;
  int len;
  
  mkin = buf->inrest;
  for (len = 0; len < buf->inrestlen; len++)
    {
      mk->binhex->checksum = 
	calc_crc(mk->binhex->checksum, (unsigned char)*mkin);
      mkin++;
    } 
  mkin = buf->in;
  for (len = 0; len < buf->inlen; len++)
    {
      mk->binhex->checksum = 
	calc_crc(mk->binhex->checksum, (unsigned char)*mkin);
      mkin++;
    } 
  mk->binhex->checksum = calc_crc(mk->binhex->checksum, (unsigned char)'\0');
  mk->binhex->checksum = calc_crc(mk->binhex->checksum, (unsigned char)'\0');
  *(buf->in + buf->inlen) = getbits(mk->binhex->checksum, 16, 8);
  buf->inlen++;
  *(buf->in + buf->inlen) = getbits(mk->binhex->checksum, 8, 8);
  buf->inlen++;
  *(buf->in + buf->inlen) = 0x00;
  buf->inlen++;
  *(buf->in + buf->inlen) = 0x00;
  buf->inlen++;

}

int
tobinhexfirst(mk, buf)
MessageStruct *mk;
BufStruct *buf;
{
  int i;
  int crc;
  char *c;

  buf->outlen = 0;
  strcpy(buf->out, "(This file must be converted with BinHex 4.0)\n:");
  buf->outlen += 47;
  buf->outpartlen += 47;
  buf->linelen = 1;

  /* Create the Header Fork */


  /* NAME */
  if (!mk->filename)
    {
#ifdef EMILDEBUG
      Mk_Log(LOG_DEBUG, "BinHex: encode: No filename, using default");
#endif
      mk->filename = newstr("noname");
      mk->filenamelen = strlen(mk->filename);
    }
  else
    {
      Mk_Log(LOG_DEBUG, "Constructing binhex filename = %s", 
	     MkMess_Curr->filename);
      if (mk->binhex->btype[0] == '\0') 
	joinextension();
    }
	
	
  *buf->inrest = mk->filenamelen;
  buf->inrestlen = 1;
  bcopy(mk->filename, buf->inrest + buf->inrestlen, mk->filenamelen);
  buf->inrestlen += mk->filenamelen;
  *(buf->inrest + buf->inrestlen) = '\0';
  buf->inrestlen++;

  /* TYPE */
  if (mk->binhex == NULL)
    mk->binhex = (BinHexStruct *)xalloc(sizeof(BinHexStruct));
  if (mk->binhex->btype[0] == '\0') {
#ifdef EMILDEBUG
      Mk_Log(LOG_DEBUG, "BinHex: encode: No Type, using default");
#endif
      strncpy(mk->binhex->btype, "TEXT", 4);
    }
  strncpy((buf->inrest + buf->inrestlen), mk->binhex->btype, 4);
  buf->inrestlen += 4;

  /* AUTHOR */
  if (mk->binhex->bauth[0] == '\0') {
#ifdef EMILDEBUG
    Mk_Log(LOG_DEBUG, "BinHex: encode: No Auth, using default");
#endif
    strncpy(mk->binhex->bauth, "ttxt", 4);
  }
  strncpy((buf->inrest + buf->inrestlen), mk->binhex->bauth, 4);
  buf->inrestlen += 4;

  /* FLAGS */
  for (i = 0; i < 2; i++)
    {
      *(buf->inrest + buf->inrestlen) = '\0';
      buf->inrestlen++;
    }

  Mk_Log(LOG_DEBUG, "Constructing BinHex file of length %i", mk->totlen);

  /* DLEN */
  *(buf->inrest + buf->inrestlen) = 
    getbits(mk->totlen, 32, 8);
  buf->inrestlen++;
  *(buf->inrest + buf->inrestlen) = 
    getbits(mk->totlen, 24, 8);
  buf->inrestlen++;
  *(buf->inrest + buf->inrestlen) = 
    getbits(mk->totlen, 16, 8);
  buf->inrestlen++;
  *(buf->inrest + buf->inrestlen) = 
    getbits(mk->totlen, 8, 8);
  buf->inrestlen++;

  /* RLEN */
  for (i = 0; i < 4; i++)
    {
      *(buf->inrest + buf->inrestlen) = '\0';
      buf->inrestlen++;
    }
      
  /* Header Checksum */
  c = buf->inrest;
  for (i = 0, crc = 0; i < buf->inrestlen; i++)
    {
      crc = calc_crc(crc, (unsigned char)*c);
      c++;
    }
  crc = calc_crc(crc, (unsigned char)'\0');
  crc = calc_crc(crc, (unsigned char)'\0');
  *(buf->inrest + buf->inrestlen) = 
    getbits(crc, 16, 8);
  buf->inrestlen++;
  *(buf->inrest + buf->inrestlen) = 
    getbits(crc, 8, 8);
  buf->inrestlen++;
  buf->inpartlen -= buf->inrestlen;
}



/*
**
**	fromuuencode(mk, buf)
**	Convert from uuencode to 8bit.
*/

fromuuencode(mk, buf)
     MessageStruct *mk;
BufStruct *buf;
{
  int p;
  unsigned long ptmk = 0;
  char *mkin;
  char *mkout;
  int binlen, binlen_in;
  int result = 0;
  

  if (!strncmp(buf->in, "end", 3)) {
    if (mk->investigate)
      mk->totlen = buf->outpartlen;
    return(DONE);
  }
    

  if (!strncmp(buf->in, "begin", 5)) {
    buf->inpartlen += buf->inlen;
    return(uuheader(mk, buf));
  }


  if (!mk_init(mk, buf, &mkin, &mkout))
    return(result);
  
  
  /* Clear bufin from beginning whitespaces, they're not used. */

  for (; isspace(*mkin); mkin++) {
    buf->inpos++;
    buf->inpartlen++;
  }
  
  buf->inlen -= clearendlf(mkin);
  /* Init */
#define DEC(c) (((c) - ' ') & 077)
  if((binlen = DEC(*buf->in)) < 0)
    {
#ifdef EMILDEBUG
      Mk_Log(LOG_ERR, 
	     "Uuencode: decode failure: length specifier out of bound: \"%i\"",
	     *buf->in);
#endif
      return(ERROR_FORMAT);
    }
  binlen_in = binlen;
  buf->inpos++;
  buf->inpartlen++;
  mkin++;
  while (buf->inpos < buf->inlen)
    {
      /* Process the next four chars */
      for (p = 0; p < 4; p++) 
	{
	  if (p)
	    ptmk = (ptmk << 6);
	  else
	    ptmk = 0;

	  if (*mkin < ' ' || *mkin > '`') {
#ifdef EMILDEBUG
	    Mk_Log(LOG_ERR, "Uuencode: decode failure: illegal character: %c",
		   *mkin);
#endif
	    return(ERROR_FORMAT); /* Fatal format error */
	  }

	  ptmk = ptmk | (63 & (*mkin - ' '));
	  mkin++;
	  buf->inpos++;
	  buf->inpartlen++;
	}
      six_to_eight(ptmk, mk, buf, p, (binlen > 3) ? 3 : binlen, ENCUUENCODE);
      binlen -= (binlen < 3) ? binlen : 3;
      if (binlen == 0)
	break;
    }
    
  buf->inpos = 0;
  buf->inrestlen = 0;
  if (mk->fpart == NULL)
    mk->fpart = get_applefile_type;

  (mk->fpart)(mk, buf);

  if (binlen) {
#ifdef EMILDEBUG
    Mk_Log(LOG_ERR, "Uuencode: decode failure: premature end of line");
#endif
    return(ERROR_LESS);
  }
  else
    {
      if (binlen_in != buf->outlen)
	buf->outlen = binlen_in;
      return(OK);
    }
}

uuheader(mk, buf)
     MessageStruct *mk;
BufStruct *buf;
{
  char *tmpbuf, *p;
  int i, l;
  tmpbuf = buf->in;
  if (strncasecmp(tmpbuf, "begin ", 6))
    {
      return(ERROR_FORMAT);
    }
  tmpbuf += 6;
  for (i = 0; i < 3; i++, tmpbuf++)
    if (*tmpbuf == '\0' || !isdigit(*tmpbuf))
      return(-1);
  if (*tmpbuf == '\0' || *tmpbuf++ != ' ')
    return(ERROR_FORMAT);
  clearend(tmpbuf);
  if (*tmpbuf == '\0')
    return(ERROR_FORMAT);
  l = strlen(tmpbuf);
  p = tmpbuf;
  for (i = 0; i < l; i++)
    {
      if (isspace(*p++))
	return(ERROR_FORMAT);
    }
  if (mk->investigate)
    setfilename(tmpbuf);
  return(OK);
}

/*
**
** touuencode(mk, buf) 
** Uuencode an 8bit message.
**
*/

int
  touuencode(mk, buf)
MessageStruct *mk;
BufStruct *buf;
{
  unsigned long ptmk = 0;
  int count;
  char *mkin;
  char *mkout;
  char *lastlen;
  bool last = FALSE;
  int plen = 0;
  int result = 0;

  buf->linelen = 0;
  buf->outlen = 0;
  buf->inpos = 0;
  /* Init */
  if (mk->first)
    {
      if (!mk->filename)
	mk->filename = (char *)newstr("noname");
      joinextension();
      sprintf(buf->out, "begin 644 %s\n", mk->filename);
      buf->outlen += 11 + strlen(mk->filename);
      buf->outpartlen += buf->outlen;
    }

  if (!mk_init(mk, buf, &mkin, &mkout)) {
    if (mk->last) {
      bcopy(" \nend", buf->out + buf->outlen, 5);
      buf->outlen += 5;
      buf->outpartlen += 5;
      *(buf->out + buf->outlen) = '\0';
      buf->linelen = 0;
    }
    return(result);
  }
  for (plen = buf->inlen - buf->inpos; plen >= 45;)
    {
      plen = 45;
      buf->outlen++;
      buf->outpartlen++;
      buf->linelen = 1;
      buf->uulen = 0;

      for (count = 0;plen > 0; mkin++, plen--)
	{
	  if (count)
	    ptmk = (ptmk << 8); /* Shift left */
	  else 
	    ptmk = 0; /* Clear bit buffer */
	  buf->uulen++;
	  /* Insert 8bit character */
	  ptmk = ptmk | (255 & *mkin);
	  count++;
	  buf->inpos++;
	  buf->inpartlen++;

	  if (count == 3) /* Written three, convert to uuencode */
	    {
	      eight_to_six(ptmk, mk, buf, count, 0, 61, ENCUUENCODE);
	      count = 0;
	    }
	}
      plen = buf->inlen - buf->inpos;
    }
  if (mk->last) 
    {
      if (buf->inpos < buf->inlen)
	{
	  lastlen = buf->out + buf->outlen;
	  buf->outlen++;
	  buf->outpartlen++;
	  buf->linelen++;
	  buf->uulen = 0;
	  plen = 0;
	  for (count = 0; buf->inpos <= buf->inlen; mkin++)
	    {
	      last = (buf->inpos == buf->inlen);
	      if (count)
		ptmk = (ptmk << 8); /* Shift left */
	      else 
		ptmk = 0; /* Clear bit buffer */
	      buf->uulen++;
	      count++;
	  
	      if (!last)
		{
		  ptmk = ptmk | (255 & *mkin);
		  buf->inpos++;
		  buf->inpartlen++;
		  plen++;
		}
	      else
		for (; count != 3; count++)
		  ptmk = (ptmk << 8); /* Shift left */
		  
		  
      
	      if (count == 3) /* Written three, convert to uuencode */
		{
		  eight_to_six(ptmk, mk, buf, count, 0, 61, ENCUUENCODE);
		  count = 0;
		}
	      if (last)
		break;
	    }
	  if (plen == 0)
	    *lastlen = '\140';
	  else
	    *lastlen = (char)plen + '\40';
	}
      if  (*(buf->out + buf->outlen - 1) != '\n')
	{
	  *(buf->out + buf->outlen) = '\n';
	  buf->outlen++;
	  buf->outpartlen++;
	}
      bcopy(" \nend\n", buf->out + buf->outlen, 6);
      buf->outlen += 6;
      buf->outpartlen += 6;
      *(buf->out + buf->outlen) = '\0';
      buf->linelen = 0;

    }
  else /* !mk->last */
    {
      if ((plen = buf->inlen - buf->inpos))
	{
	  bcopy(mkin, buf->inrest, plen);
	  buf->inrestlen = plen;
	}
      else
	{
	  *buf->inrest = '\0';
	  buf->inrestlen = 0;
	}
      if (buf->outlen == 1)
	buf->outlen = 0;
    }
}


/*
**
**	buf->init()
**	Initialize the mk structure for a new line to be converted.
*/

mk_init(mk, buf, mkin, mkout)
MessageStruct *mk;
BufStruct *buf;
     char **mkin;
     char **mkout;
{

  if (buf->in == NULL || (!buf->inlen && !buf->inrestlen && mk->last)) 
    /* NULL input */
    {
      return(0);
    }

  if (buf->inrestlen > 0)
    /* Some leftovers from last run */
    {
      *mkin = buf->inrest;
      bcopy(buf->in + buf->inpos, *mkin + buf->inrestlen, buf->inlen - buf->inpos);
      buf->inlen += buf->inrestlen;
      buf->inrestlen = 0;
    }
  else
    *mkin = buf->in + buf->inpos;
  *(*mkin + buf->inlen) = '\0';
  if (buf->inpos == buf->inlen) {
    /* Empty line */
    return(0);
  }
  if (buf->out)
    *mkout = buf->out + buf->outlen;

  *(buf->in + buf->inlen) = '\0';

  return(1);
}


six_to_eight(sixes, mk, buf, count, maxlen, type)
     long sixes;
     MessageStruct *mk;
     BufStruct *buf;
     int count;
     int maxlen;
     int type;
{
  int i, n;
  if (count == 0)
    return(0);
  if (count == 2)
    sixes = (sixes >> 4);
  if (count == 3)
    sixes = (sixes >> 2);
    
  for (i = count - 1; i > 0; i--)
    {
      if (maxlen)
	{
	  *(buf->out + buf->outlen) = (char)getbits(sixes, i * 8, 8);
	  if (type == ENCBINHEX)
	    {
	      if (mk->binhex->run)
		{
		  mk->binhex->run = FALSE;
		  if (*(buf->out + buf->outlen) == 0x00)
		    {
		      *(buf->out + buf->outlen) = 0x90;
		      mk->binhex->lastrun = 0x90;
		      buf->outlen++;
		    }
		  else {
		    for (n = *(buf->out + buf->outlen); n > 1; n--)
		      {
			*(buf->out + buf->outlen) = mk->binhex->lastrun;
			buf->outlen++;
			buf->outpartlen++;
		      }
		  }
		}
	      else
		{
		  if ((unsigned char )*(buf->out + buf->outlen) == 0x90) {
		    mk->binhex->run = TRUE;
		    ccc++;
		  }
		  else
		    {
		      mk->binhex->lastrun = *(buf->out + buf->outlen);
		      buf->outlen++;
		      buf->outpartlen++;
		      maxlen--;
		    }
		}
	    }
	  else
	    {
	      buf->outlen++;
	      buf->outpartlen++;
	      maxlen--;
	    }
	}
    }

}

eight_to_six(eights, mk, buf, count, base, linelen, type)
     unsigned long eights;
     MessageStruct *mk;
     BufStruct *buf;
     int count;
     char base[];
     int linelen;
     int type;

{
  int i;
  if (count == 0)
    return(0);
  if (count == 1)
    eights = (eights << 4);
  if (count == 2)
    eights = (eights << 2);
      
  for (i = count + 1; i > 0; i--)
    {
      if (type == ENCUUENCODE) 
	{
	  short uu;
	  uu = (63 & getbits(eights, i * 6, 6));
	  if (uu == 0)
	    *(buf->out + buf->outlen) =  '\140';
	  else
	    *(buf->out + buf->outlen) =  (char) (uu + '\40');
	}
      else
	*(buf->out + buf->outlen) = (char) base[(63 & getbits(eights, i * 6, 6))];
      buf->outlen++;
      buf->outpartlen++;
      buf->linelen++;
      if (linelen == buf->linelen)
	{
	  *(buf->out + buf->outlen) = '\n';
	  if (type == ENCUUENCODE)
	    {
	      if (buf->uulen == 0)
		*(buf->out + buf->outlen - buf->linelen) = '\140';
	      else
		*(buf->out + buf->outlen - buf->linelen) = 
		  (char)(buf->uulen + '\40');
	    }
	  buf->linelen = 0;
	  buf->outlen++;
	  buf->outpartlen++;
	}
      *(buf->out + buf->outlen) = '\0';
    }
}




