/*
**
** Copyright (C) 1994 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
**                                        Torbjorn.Wictorin@udac.uu.se
**
**                                        UDAC	
**                                        P.O. Box 174
**                                        S-751 04 Uppsala
**                                        Sweden
**
*/


#include "emil.h"

#include "charset/strncnv.c"
int     strptrncnv(CHARSET *, CHARSET *, struct data *, struct data *, int);

int
tocharset(struct message *m)
{
  CHARSET *schar, *tchar;
  struct data *inbuf, *outbuf;
  char *sset, *tset;
  int copy = 0;

  inbuf = m->td;

#ifdef DEBUG
  if (edebug)
    fprintf(stderr, "* Tocharset");
#endif
  if (inbuf->size == 0)
    {
#ifdef DEBUG
      if (edebug)
	fprintf(stderr, "--- Empty input (failed).\n");
#endif
      return(NOK);
    }
  sset = m->td->charset;
#ifdef DEBUG
  if (edebug)
    {
      if (sset == NULL)
	fprintf(stderr, "Source charset is NULL\n");
      else
	fprintf(stderr, "Source charset is %s\n", sset);
    }
#endif
  if (sset != NULL)
    {
      if ((strncasecmp(sset, "ISO-8859-", 9) == 0) && 
	  m->td->encoding == E7BIT)
	{
	  m->td->charset = NEWSTR("US-ASCII");
	  return(OK);
	}
      if (cmatch(sset, "US-ASCII"))
	return(OK);
    }
  if (target->itext == E7BIT || target->itext == ESE)
    tset = NEWSTR("ISO-8859-1");
  else
    {
      tset = target->charset;
      if (cmatch(sset, tset))
	copy = 1;
    }
  if (sset == NULL || tset == NULL ||
      (schar = (CHARSET *)getchset(sset, 29)) == NULL ||
      (tchar = (CHARSET *)getchset(tset, 29)) == NULL)
    copy = 1;
  if (schar != NULL && schar->cs->bits == 7 && inbuf->encoding == E8BIT)
    {
#ifdef DEBUG
      if (edebug)
	fprintf(stderr, ", corrupt charset specification.\n");
#endif
      logger(LOG_DEBUG, "tocharset: corrupt source charset specification");
      return(NOK);
    }

      
  if (copy)
    {
#ifdef DEBUG
  if (edebug)
    fprintf(stderr, ", copying (failed).\n");
#endif
      logger(LOG_DEBUG, "tocharset: just copying");
      return(NOK);
    }
  else
    {
#ifdef DEBUG
  if (edebug)
    fprintf(stderr, ", from %s to %s",
	    sset, tset);
#endif
      outbuf = (struct data *) Yalloc(sizeof(struct data ));
      strptrncnv(tchar, schar, outbuf, inbuf, pz);
      outbuf->bodyend = outbuf->end;
      outbuf->charset = NEWSTR(tset);
      outbuf->lineend = inbuf->lineend - inbuf->linestart;
      safe_mchange(m, outbuf);
    }
  if (target->itext == E7BIT)
    {
      m->td->offset = m->td->bodystart;
      to_stripped(m);
      m->td->charset = target->charset;
    }
  if (target->itext == ESE)
    {
      m->td->offset = m->td->bodystart;
      to_7bit(m);
      m->td->charset = target->charset;
    }
  check_bits(m->td);
  if (m->td->encoding == E7BIT && 
      (m->td->charset == NULL || strncasecmp(m->td->charset, "ISO-8859-", 9 ) == 0))
    m->td->charset = NEWSTR("US-ASCII");
#ifdef DEBUG
  if (edebug)
    fprintf(stderr, ", done.\n");
#endif
  
  return(OK);
}

int
  strptrncnv(register CHARSET *r_chset, register CHARSET *s_chset, 
	     struct data *outbuf, struct data *inbuf, int busize)
{
  CHAR8U	 *source;
  CHAR8U	c, c1;
  /* 4 chars for ending: esc two-char nul */
  int	o;		/* intermediate binary value */
  /* INT16S	mnem; ... Unused ... 941114 / TW */
  int	oc; 		/* 2-byte output value */
  int 	bytes;
  int	gotesc2;
  
  source = (CHAR8U *) (inbuf->contents + inbuf->offset);

  bytes = r_chset->cs->outbytes; 
  gotesc2= 0;

  while ((c = *source++) diff 0 && inbuf->offset < inbuf->bodyend) {
    inbuf->offset += 1;

    if (c == s_esc and (! s_esc2 || s_esc2 == *source)) 
      {
	if (s_esc2) 
	  {
	    inbuf->offset += 1;
	    source++;
	  }
	/* Two esc in a row -> one escape
	 * If esc followed by defined mnemonic,
	 * next char is mnemonic.  */
	if (*source == s_esc and (! s_esc2 || s_esc2 == *(source+1))) 
	  {
	    if (s_esc2) 
	      gotesc2++;
	    o = *(s_in + s_esc);
	    /* handle 2 escs */
	    source++;
	    inbuf->offset += 1;
	    if (s_esc2) 
	      {
		inbuf->offset += 1;
		source++;
	      }

	  }
	else 
	  { /* mnemonic */
	    inbuf->offset += 1;
	    c = *source++;
	    if (c == '_') 
	      { 
		/* long ?? */ 
	      }
	    else 
	      {
		c1 = *source++;
		inbuf->offset += 1;
		o = *(ot1+*(s_in+c)) + *(ot2+*(s_in+c1));

	      }
	  }
      }
    else 
      o = *(s_in + c);
    

    if (o > hdr.outsize) /* special handling */ 
      {
	if (o < hdr.begcombtabs ) /* long mnem */ 
	  {
	  }
	else 
	  { /* combtabs */
	    c1 = *source++;
	    inbuf->offset += 1;

	    o=(char)*(s_in + (o-hdr.begcombtabs+1)*C256 +c1);

	  }
      }
    if (! o) 
      o = 141; /* if not defined: underline */
    
    if (bytes ==2) 
      oc= *((INT16S *) r_out + o);
    else 
      oc= *(r_out + o);
    if (gotesc2) {
      gotesc2= *(s_in+s_esc2);
      if (! gotesc2) 
	gotesc2= 141;

      if (bytes ==2) 
	gotesc2= *((INT16S *) r_out + gotesc2);
      else 
	gotesc2= *(r_out + gotesc2);
      oc = oc *C256 + gotesc2;
      gotesc2=0;
    }

    if (oc == r_esca) 
      { /* write 2 escs */
	append_char(outbuf, r_esc, busize);
	if (r_esc2) 
	  append_char(outbuf, r_esc2, busize);
	append_char(outbuf, r_esc, busize);
	if (r_esc2) 
	  append_char(outbuf, r_esc2, busize);

      }
    else 
      if (oc) 
	{
	  if (oc/C256) 
	    append_char(outbuf, oc>>8, busize);
	  append_char(outbuf, oc%C256, busize);

	}
      else 
	{
	  append_char(outbuf, r_esc, busize);
	  if (r_esc2) 
	    append_char(outbuf, r_esc2, busize);
	  if (bytes == 2) 
	    {
	      append_char(outbuf, *((INT16S *)r_out + hdr.basechrs + o%hdr.basechrs), busize);
	      append_char(outbuf, *((INT16S *)r_out + hdr.basechrs + o/hdr.basechrs), busize);
	    }
	  else 
	    {
	      append_char(outbuf, *(r_out + hdr.basechrs + o%hdr.basechrs), busize);
	      append_char(outbuf, *(r_out + hdr.basechrs + o/hdr.basechrs), busize);
	    }

	}

  }
  return (OK);
}
