/*
 *
 * 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"

char *get_type();
char *get_encoding();
BoundStruct *addbound();
BoundStruct *addendbound();

/*
 * Message part encodings structure
 */

static TypeStruct MkEncodings[] = {
  {"7BIT", ENC7BIT},
  {"8BIT", ENC8BIT},
  {"BINARY", ENCBINARY},
  {"BASE64", ENCBASE64},
  {"QUOTED-PRINTABLE", ENCQUOTEDPRINTABLE},
  {"UUENCODE", ENCUUENCODE},
  {"BINHEX", ENCBINHEX},
  {(char *)NULL, ENCUNKNOWN}
};

/*
 * Message part types structure
 */

static TypeStruct MkTypes[] = {
  {"TEXT", TYPETEXT},
  {"APPLICATION", TYPEAPPLICATION},
  {"IMAGE", TYPEIMAGE},
  {"AUDIO", TYPEAUDIO},
  {"VIDEO", TYPEVIDEO},
  {"MULTIPART", TYPEMULTIPART},
  {"MESSAGE", TYPEMESSAGE},
  {"EXTERNAL", TYPEEXTERNAL},
  {"BINHEX", TYPEBINHEX},
  {"APPLESINGLE", TYPEAPPLESINGLE},
  {"APPLEDOUBLE", TYPEAPPLEDOUBLE},
  {(char *)NULL, TYPEUNKNOWN},
};



/*
**
**	TCL-command: debug "string"
**
**	Writes to MkLogFile by Mk_Log().
**
*/

int
Mk_Debug(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  int i;
  char *cp;
  char line[BUFSIZE];
  strcpy(line, "TCL-DEBUG: ");
  if (argc == 1) {
    Tcl_AppendResult(interp, "debug: wrong # args: should be \"", 
		     argv[0], " Vars\"", (char *) NULL);
    return TCL_ERROR;
  }
  
  for(i = 1; i < argc; i++) {
    cp = (char *)Tcl_GetVar(interp, argv[i], TCL_LEAVE_ERR_MSG);
    if (cp == NULL) {
      cp = (char *)argv[i];
    }
    strcat(line, cp);
    strcat(line, " ");
  }
#ifdef EMILDEBUG
  Mk_Log(LOG_DEBUG, line);
#endif
  return TCL_OK;
}

/*
**
**	TCL-command: to7bit
**
**	Adds function to7bit to MkMess_Buf list.
**
*/

int
Mk_To7Bit(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{

  if (argc != 1) {
    Tcl_AppendResult(interp, "to7bit: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }
  addfunc(to7bit, "to7bit");

  return TCL_OK;
}


/*
**
**	TCL-command: getheader "Field"
**
**	Returns the value of "Field"-header if any.
**
*/

int
Mk_Getheader(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  char *s;
  if (argc != 2) {
    Tcl_AppendResult(interp, "getheader: wrong # args: should be \"", 
		     argv[0], " Field\"", (char *) NULL);
    return TCL_ERROR;
  }
  if ((s = (char *)mkhvalue(argv[1], MkMess_Curr->header)) == (char *)NULL) 
    Tcl_SetResult(interp, "0", TCL_STATIC);
  else
    Tcl_SetResult(interp, s, TCL_STATIC);
  return TCL_OK;
}


/*
**	TCL-command: hasbody
**
**	Returns TRUE if MkMess_Curr contains output lines.
**
*/

int
Mk_HasBody(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 1) {
    Tcl_AppendResult(interp, "hasbody: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }
  if (MkMess_Curr->start_line < MkMess_Curr->end_line)
    Tcl_SetResult(interp, "1", TCL_STATIC);
  else
    Tcl_SetResult(interp, "0", TCL_STATIC);
  return TCL_OK;
}


/*
**	TCL-command: killbody
**
**      Removes the current MessageStruct from list.
**
*/

int
Mk_KillBody(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 1) {
    Tcl_AppendResult(interp, "killbody: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }

  if (MkMess_Curr ==  MkMess_Root) {
    Tcl_AppendResult(interp, "killbody: Can't kill the root bodypart", 
		     (char *) NULL);
    return TCL_ERROR;
  }
  if (MkMess_Curr->start_line < MkMess_Curr->end_line) {
    Tcl_AppendResult(interp, "killbody: Can't kill nonempty bodypart", 
		     (char *) NULL);
    return TCL_ERROR;
  }
  else
    {
      MessageStruct *last, *curr;
      for(curr = MkMess_Root; curr != NULL; curr=curr->next)
	{
	  if (curr == MkMess_Curr)
	    break;
	  else
	    last = curr;
	}
      if (last)
	last->next = MkMess_Curr->next;
    }
  MkMess_Curr = MkMess_Curr->next;
  MkMess_Buf = MkMess_Curr->buf;
  return TCL_OK;
}


/*
**	TCL-command: joinextension
**
**	Adds extension to filename if any.
**
*/

int
Mk_JoinExtension(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 1) {
    Tcl_AppendResult(interp, "joinextension: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }
  joinextension();
  Tcl_SetResult(interp, "1", TCL_STATIC);
  return TCL_OK;
}




/*
**
**	TCL-command: nextmessnode
**
**	Make the next MessNode in the list the active MessNode.
**
*/

int
Mk_NextMessNode(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 1) {
    Tcl_AppendResult(interp, "nextmessnode: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }
  if (MkMess_Root->investigate) {
    Tcl_AppendResult(interp, "nextmessnode: Rejected while in investigate mode",
		      (char *) NULL);
    return TCL_ERROR;
  }
  if (MkMess_Curr->next == NULL) {
#ifdef EMILDEBUG
    Mk_Log(LOG_DEBUG, "Next messnode failed");
#endif
    Tcl_SetResult(interp, "0", TCL_STATIC);
  }
  else {
#ifdef EMILDEBUG
    Mk_Log(LOG_DEBUG, "Next messnode");
#endif
    MkMess_Curr = MkMess_Curr->next;
    MkMess_Buf = MkMess_Curr->buf;
    Tcl_SetResult(interp, "1", TCL_STATIC);
  }
  return TCL_OK;
    

}


/*
**
**	TCL-command: insertmessnode
**
**	Insert an empty MessNode before the current and make it active.
**
*/

int
Mk_InsertMessNode(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  MessageStruct *mess, *prev;
  if (argc != 1) {
    Tcl_AppendResult(interp, "nextmessnode: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }
  if (MkMess_Root->investigate) {
    Tcl_AppendResult(interp, "insertmessnode: Rejected while in investigate mode",
		     (char *) NULL);
    return TCL_ERROR;
  }
  for (mess = MkMess_Root; mess != NULL; mess = mess->next)
    {
      if (mess == MkMess_Curr)
	break;
      prev = mess;
    }
  
  if ((mess = (MessageStruct *)mkmessalloc()) == NULL) 
    {
#ifdef EMILDEBUG
      Mk_Log(LOG_ERR, "Insert messnode: mkmessalloc failed");
#endif
      Tcl_SetResult(interp, "0", TCL_STATIC);
    }
  else
    {
#ifdef EMILDEBUG
      Mk_Log(LOG_ERR, "Inserting messnode");
#endif
      mess->next = (MessageStruct *)MkMess_Curr;
      prev->next = (MessageStruct *)mess;
      MkMess_Curr = mess;	
      MkMess_Buf = MkMess_Curr->buf;
      Tcl_SetResult(interp, "1", TCL_STATIC);
    }
  return TCL_OK;
}





/*
**
**	TCL-command: topmessnode
**
**	Make the first MessNode in the list the active MessNode.
**
*/

int
Mk_TopMessNode(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 1) {
    Tcl_AppendResult(interp, "topmessnode: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }
  if (MkMess_Curr->investigate) {
    Tcl_AppendResult(interp, "topmessnode: Rejected while in investigate mode",
		      (char *) NULL);
    return TCL_ERROR;
  }

  if (MkMess_Root == NULL) {
#ifdef EMILDEBUG
    Mk_Log(LOG_DEBUG, "topmessnode failed");
#endif
    Tcl_SetResult(interp, "0", TCL_STATIC);
  }
  else {
#ifdef EMILDEBUG
    Mk_Log(LOG_DEBUG, "topmessnode");
#endif
    MkMess_Curr = MkMess_Root;
    MkMess_Buf = MkMess_Curr->buf;
    Tcl_SetResult(interp, "1", TCL_STATIC);
  }
  return TCL_OK;
    

}



/*
**
**	TCL-command: knowfromcharset
**
**	Returns TRUE if fromcharset is specified for this messagepart
**	or for this message.
**
*/

int
Mk_KnowFromCharset(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 1) {
    Tcl_AppendResult(interp, "knowfromcharset: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }
  if (MkMess_Curr->fcharset || MkMess_Root->fcharset)
    Tcl_SetResult(interp, "1", TCL_STATIC);
  else
    Tcl_SetResult(interp, "0", TCL_STATIC);
  return TCL_OK;
}


/* 
**
**	TCL-command: listheaders
**
**	List the fields of the header list for MkMess_Curr.
**
*/

int
Mk_ListHeaders(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 1) {
    Tcl_AppendResult(interp, "listheaders: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }
  interp->result = (char *)Tk_HFieldMerge(MkMess_Curr->header);
  return TCL_OK;
}



/*
**
**	TCL-command: addheader "Field" "Value"
**
**	Make a header line of field and value and add to the header list
**	of MkMess_Curr
**
*/

int
Mk_AddHeader(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  char *sh;
  if (argc != 3) {
    Tcl_AppendResult(interp, "addheader: wrong # args: should be \"", 
		     argv[0], " Field Value\"", (char *) NULL);
    return TCL_ERROR;
  }
  

  sh = (char *)xalloc(strlen(argv[1]) + strlen(argv[2]) + 3);
  sprintf(sh, "%s: ", argv[1]);
  strcat(sh, argv[2]);
  Mk_Log(LOG_DEBUG, "Adding header: %s", sh);
  if(storeheader(sh, MkMess_Curr) < 0) {
    Tcl_AppendResult(interp, "storeheader: store Error");
    return TCL_ERROR;
  }
  else
    return TCL_OK;
}

/*
**
**	TCL-command: addspecheader "Field"
**
**	Add field to the specheader list of MkMess_Curr.
**	(These headers may be removed from the header list by
**	TCL-command "rmspecheader"
**
*/

int
Mk_AddSpecHeader(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 2) {
    Tcl_AppendResult(interp, "addspecheader: wrong # args: should be \"", 
		     argv[0], " Field\"", (char *) NULL);
    return TCL_ERROR;
  }
  

  if(storespecheader(argv[1], MkMess_Curr) < 0) {
    Tcl_AppendResult(interp, "storespecheader: store Error");
    return TCL_ERROR;
  }
  else
    return TCL_OK;
}



/*
**
**	TCL-command: rmheader "Field"
**
**	Remove the header line specified by the argumentet header field from
**	the header list of MkMess_Curr
**
*/

int
Mk_RmHeader(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 2) {
    Tcl_AppendResult(interp, "rmheader: wrong # args: should be \"", 
		     argv[0], " Field\"", (char *) NULL);
    return TCL_ERROR;
  }
  
  removeheader(argv[1], MkMess_Curr->header);
  return TCL_OK;
}

/*
**
**	TCL-command: rmspecheader
**
**	Remove the headers in specheader list of MkMess_Curr from
**	header list of MkMess_Curr
**
*/

int
Mk_RmSpecHeader(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  SpecHeaderStruct *sh;
  if (argc != 1) {
    Tcl_AppendResult(interp, "rmspecheader: wrong # args: should be \"", 
		     argv[0], " \"", (char *) NULL);
    return TCL_ERROR;
  }
  
  for (sh = MkMess_Curr->specheader; sh != NULL; sh = sh->next)
    {
      if (sh->name) 
	removeheader(sh->name, MkMess_Curr->header);
    }
  return TCL_OK;
}

/*
**
**	TCL-command: settype "TYPE"
**
**	Set type of MkMess_Curr to any of the types in types strucuture
**	(above).
**
*/

int
Mk_SetType(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  TypeStruct *types;
  if (argc != 2) {
    Tcl_AppendResult(interp, "settype: wrong # args: should be \"", 
		     argv[0], " Type\"", (char *) NULL);
    return TCL_ERROR;
  }
  
  for (types = MkTypes; types->name != NULL; types++) 
    if (!strcasecmp(argv[1], types->name))
      break;
  MkMess_Curr->type = types->type;
  return TCL_OK;
}

/*
**
**	TCL-command: setmaintype "TYPE"
**
**	Set maintype of MkMess_Curr to "TYPE"
**
*/

int
Mk_SetMainType(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 2) {
    Tcl_AppendResult(interp, "setmaintype: wrong # args: should be \"", 
		     argv[0], " Type\"", (char *) NULL);
    return TCL_ERROR;
  }
  
  MkMess_Root->maintype = newstr(argv[1]);
  return TCL_OK;
}

/*
**
**	TCL-command: setsubtype "TYPE"
**
**	Set subtype of MkMess_Curr to "TYPE"
**
*/

int
Mk_SetSubType(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 2) {
    Tcl_AppendResult(interp, "setsubtype: wrong # args: should be \"", 
		     argv[0], " Type\"", (char *) NULL);
    return TCL_ERROR;
  }
  
  MkMess_Curr->subtype = newstr(argv[1]);
  return TCL_OK;
}

/*
**	TCL-command: setcheck BINHEX | UUENCODE
**
**	Program check for BinHex and uuencode in message.
**
*/

int
Mk_SetCheck(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 2) {
    Tcl_AppendResult(interp, "setcheck: wrong # args: should be \"", 
		     argv[0], " uuencode | binhex\"", (char *) NULL);
    return TCL_ERROR;
  }
  
  if (!strcasecmp(argv[1], "binhex"))
    {
      checkbinhex = TRUE;
    }
  else
  if (!strcasecmp(argv[1], "uuencode"))
    {
      checkuuencode = TRUE;
    }
  else
    {
      Tcl_AppendResult(interp, "setcheck: unknown check type: \"",
		       argv[1],
	       "\"choose between \"BinHex or uuencode\"", (char *) NULL);
      return TCL_ERROR;
    }

  return TCL_OK;
}


/*
**
**	TCL-command: gettype
**
**	Return type of MkMess_Curr
**
*/

int
Mk_GetType(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 1) {
    Tcl_AppendResult(interp, "gettype: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }
  
  Tcl_SetResult(interp, (char *)get_type(), TCL_STATIC);
  return TCL_OK;
}

char * 
get_type()
{
  TypeStruct *types;
  for (types = MkTypes; types->name != NULL; types++) 
    if (MkMess_Curr->type == types->type)
      break;
  return(types->name);
}

/*
**
**	TCL-command: getmaintype
**
**	Return maintype of MkMess_Curr
**
*/


int
Mk_GetMainType(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 1) {
    Tcl_AppendResult(interp, "getmaintype: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }
  if (MkMess_Root->maintype)
    Tcl_SetResult(interp, MkMess_Root->maintype, TCL_STATIC);
  else
    Tcl_SetResult(interp, "0", TCL_STATIC);
  return TCL_OK;
}

/*
**
**	TCL-command: getsubtype
**
**	Return subtype of MkMess_Curr
**
*/

int
Mk_GetSubType(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 1) {
    Tcl_AppendResult(interp, "getsubtype: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }
  if (MkMess_Curr->subtype)
    Tcl_SetResult(interp, MkMess_Curr->subtype, TCL_STATIC);
  else
    Tcl_SetResult(interp, "0", TCL_STATIC);
  return TCL_OK;
}

/*
**
**	TCL-command: getencoding
**
**	Return encoding of MkMess_Curr
**
*/

int
Mk_GetEncoding(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 1) {
    Tcl_AppendResult(interp, "getencoding: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }
  
  Tcl_SetResult(interp, get_encoding(), TCL_STATIC);
  return TCL_OK;
}
char *
get_encoding()
{
  TypeStruct *encodings;
  for (encodings = MkEncodings; encodings->name != NULL; encodings++) 
    if (MkMess_Curr->enc == encodings->type)
      break;
  return(encodings->name);
}

/*
**
**	TCL-command: setfromcharset "CHARSET"
**
**	Set fromcharset of MkMess_Curr to "CHARSET"
**
*/

int
Mk_SetFromCharset(clientData, interp, argc, argv)
     ClientData clientData;
     Tcl_Interp *interp;
     int argc;
     char *argv[];
{
  if (argc != 2) {
    Tcl_AppendResult(interp, "setfromcharset: wrong # args: should be \"", 
		     argv[0], " FromCharset\"", (char *) NULL);
    return TCL_ERROR;
  }
  MkMess_Curr->fcharset = newstr(argv[1]);
#ifdef EMILDEBUG
  Mk_Log(LOG_DEBUG, "Setting fromcharset to %s", argv[1]);
#endif
  return TCL_OK;
}

/*
**
**	TCL-command: setfromesc INTEGER
**
**	Set Escape for charset conversion of MkMess_Curr.
**
*/

int
Mk_SetFromEsc(clientData, interp, argc, argv)
     ClientData clientData;
     Tcl_Interp *interp;
     int argc;
     char *argv[];
{
  if (argc != 2) {
    Tcl_AppendResult(interp, "setfromesc: wrong # args: should be \"", 
		     argv[0], " FromEsc\"", (char *) NULL);
    return TCL_ERROR;
  }
  MkMess_Curr->esc = (short)atoi(argv[1]);
  return TCL_OK;
}

/*
**
**	TCL-command: tocharset "CHARSET"
**
**	Set tocharset for conversion to "CHARSET"
**
*/

int
Mk_ToCharset(clientData, interp, argc, argv)
     ClientData clientData;
     Tcl_Interp *interp;
     int argc;
     char *argv[];
{
  if (argc < 2 || argc > 3) {
    Tcl_AppendResult(interp, "tocharset: wrong # args: should be \"", 
		     argv[0], 
		     " [FromCharset] ToCharset\"", (char *) NULL);
    return TCL_ERROR;
  }
  /* Check and set escape char */
  if (MkMess_Curr->esc == 0)
    if (MkMess_Root->esc)
      MkMess_Curr->esc = MkMess_Root->esc;
    else
      MkMess_Curr->esc = 29;


  if (argc == 2) 
    {
      MkMess_Curr->tcharset = newstr(argv[1]);
      if (!MkMess_Curr->fcharset && MkMess_Root->fcharset)
	MkMess_Curr->fcharset = MkMess_Root->fcharset;
    }
  if (argc == 3)
    {
      MkMess_Curr->fcharset = newstr(argv[1]);
      MkMess_Curr->tcharset = newstr(argv[2]);
    }

  if (MkMess_Curr->fcharset == NULL)
    {
      Mk_Log(LOG_DEBUG, "No fromcharset specified, charset conversion failed");
      Tcl_SetResult(interp, "0", TCL_STATIC);
      return TCL_OK;
    }
  if (MkMess_Curr->tcharset == NULL)
    {
      Mk_Log(LOG_DEBUG, "No tocharset specified, charset conversion failed");
      Tcl_SetResult(interp, "0", TCL_STATIC);
      return TCL_OK;
    }

  if (strcasecmp(MkMess_Curr->tcharset, MkMess_Curr->fcharset)) {
#ifdef EMILDEBUG
    Mk_Log(LOG_DEBUG, "Setting tocharset to %s", MkMess_Curr->tcharset);
    Mk_Log(LOG_DEBUG, "Setting fromcharset to %s", MkMess_Curr->fcharset);
#endif
  }
  else {
#ifdef EMILDEBUG
    Mk_Log(LOG_DEBUG, "No charset conversion necessery");
#endif
  }


  if ((MkMess_Curr->from_charset = 
       (CHARSET *)getchset(MkMess_Curr->fcharset,
			   MkMess_Curr->esc)) == NULL) 
    {

      Mk_Log(LOG_DEBUG, "fromcharset: unknown fromcharset: %s",
	     MkMess_Curr->fcharset);
      Tcl_SetResult(interp, "0", TCL_STATIC);
      return TCL_OK;
    }

  if ((MkMess_Curr->to_charset = 
       (CHARSET *)getchset(MkMess_Curr->tcharset, 
			   MkMess_Curr->esc)) == NULL) 
    {
      Mk_Log(LOG_DEBUG, "tocharset: unknown tocharset: %s",
	     MkMess_Curr->fcharset);
      Tcl_SetResult(interp, "0", TCL_STATIC);
      return TCL_OK;
    }

  addfunc(tocharset, "tocharset");
  Tcl_SetResult(interp, "1", TCL_STATIC);
  return TCL_OK;
}


/*
**
**	TCL-command: encode "ENCODING"
**
**	Add encode to "ENCODING" in MkMess_Cuf list.
**
*/

int
Mk_Encoding(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 2) {
    Tcl_AppendResult(interp, "encode: wrong # args: should be \"", argv[0], 
		     " Encoding\"", (char *) NULL);
    return TCL_ERROR;
  }
  /* BinHex */
  if (!strcasecmp(argv[1], "BinHex"))
    {
      addfunc(tobinhex, "tobinhex");
    }
  else
  /* UUEncode */
  if (!strcasecmp(argv[1], "UUEncode"))
    {
      addfunc(touuencode, "touuencode");
    }
  else
  /* Base 64 */
  if (!strcasecmp(argv[1], "Base64"))
    {
      addfunc(tobase64, "tobase64");
    }
  else
  /* Quoted-Printable */
  if (!strcasecmp(argv[1], "Quoted-Printable"))
    {
      addfunc(toquotedp, "toquotedp");
    }
  else
    {
      Tcl_AppendResult(interp, "encode: unknown encoding", (char *)NULL);
      return TCL_ERROR;
    }
#ifdef EMILDEBUG
  Mk_Log(LOG_DEBUG, "Setting encode to %s", argv[1]);
#endif
  return TCL_OK;
}

/*
**
**	TCL-command: decode
**
**	Add decode of MkMess_Curr's encoding to MkMess_Buf list.
**
*/

int
Mk_Decoding(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 2) {
    Tcl_AppendResult(interp, "decode: wrong # args: should be \"", argv[0], 
		     " Encoding\"", (char *) NULL);
    return TCL_ERROR;
  }
  
  /* BinHex */
  if (!strcasecmp(argv[1], "BinHex"))
    {
      addfunc(frombinhex, "frombinhex");
    }
  else
  /* UUEncode */
  if (!strcasecmp(argv[1], "UUEncode"))
    {
      addfunc(fromuuencode, "fromuuencode");
    }
  else
  /* Base 64 */
  if (!strcasecmp(argv[1], "Base64"))
    {
      addfunc(frombase64, "frombase64");
    }
  else
  /* Quoted-Printable */
  if (!strcasecmp(argv[1], "Quoted-Printable"))
    {
      addfunc(fromquotedp, "fromquotedp");
    }
  else
    {
      Tcl_AppendResult(interp, "decode: unknown encoding", (char *)NULL);
      return TCL_ERROR;
    }
#ifdef EMILDEBUG
  Mk_Log(LOG_DEBUG, "Setting decode from %s", argv[1]);
#endif
  return TCL_OK;
}


int
addfunc(func, name)
int (*func)();
char *name;
{
  if (!MkMess_Buf->fconv) 
    {
#ifdef EMILDEBUG
      Mk_Log(LOG_DEBUG, "Adding func %s", name);
#endif
      MkMess_Buf->fconv = func;
      MkMess_Buf->name = newstr(name);
      return(mkaddbufnode());
    }
  else
    {
      MkMess_Buf = MkMess_Buf->next;
      MkMess_Buf->name = newstr(name);
      return(addfunc(func));
    }
}


/*
**
**	TCL-command: addboundary "BOUNDARY"
**
**	Add "BOUNDARY" to boundary list of MkMess_Root
**
*/

int
Mk_AddBoundary(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 2) {
    Tcl_AppendResult(interp, "addboundary: wrong # args: should be \"", argv[0], 
		     " Boundary\"", (char *) NULL);
    return TCL_ERROR;
  }
  MkMess_Root->bound = (BoundStruct *)addbound(argv[1], MkMess_Root->bound);
#ifdef EMILDEBUG
  Mk_Log(LOG_DEBUG, "Setting boundary=%s", argv[1]);
#endif
  return TCL_OK;
}

BoundStruct *
addbound(new, bounds)
     char *new;
     BoundStruct *bounds;
{
  BoundStruct *tb;
  tb = (BoundStruct *)xalloc(sizeof(BoundStruct));
  tb->name = (char *)newstr(new);
  tb->namelen = strlen(new);
  tb->next = bounds;
  MkMess_Curr->topofmulti = TRUE;
  MkMess_Curr->newbound = TRUE;
  if (!MkMess_Boundary)
    MkMess_Boundary = tb;
  return(tb);
}

/*
**
**	TCL-command: addendboundary "BOUNDARY"
**
**	Add "BOUNDARY" to endboundary list of MkMess_Root.
**
*/

int
Mk_AddEndBoundary(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 2) {
    Tcl_AppendResult(interp, "addendboundary: wrong # args: should be \"", argv[0], 
		     " Boundary\"", (char *) NULL);
    return TCL_ERROR;
  }
#ifdef EMILDEBUG
  Mk_Log(LOG_DEBUG, "Setting end boundary=%s", argv[1]);
#endif
  MkMess_Root->bound = (BoundStruct *)addendbound(argv[1], MkMess_Root->bound);

  return TCL_OK;
}

BoundStruct *
addendbound(new, bounds)
     char *new;
     BoundStruct *bounds;
{
  BoundStruct *tb;
  if (bounds == NULL)
    {
      tb = (BoundStruct *)xalloc(sizeof(BoundStruct));
    }
  else
    {
      tb = bounds;
    }
  tb->lend = (char *)newstr(new);
  tb->endlen = strlen(new);
  return(tb);
}

/*
**
**	TCL-command: makeboundary
**
**	Return a boundary
**
*/

int
Mk_MakeBoundary(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  char *s;
  char bbound[71];
  static int count = 6568069;
  
  if (argc != 1) {
    Tcl_AppendResult(interp, "getboundary: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }
  count++;
  sprintf(bbound, "=================_Emil_Boundary_=============_%i==_", count);
  s = newstr(bbound);
  Tcl_SetResult(interp, s, TCL_STATIC);
  return TCL_OK;
}

/*
**
**	TCL-command: putendboundary
**
**      Set to put end boundary at the end of this body part
**
*/

int
Mk_PutEndBoundary(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 1) {
    Tcl_AppendResult(interp, "getboundary: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }
#ifdef EMILLOG
Mk_Log(LOG_DEBUG, "Activating end bound");
#endif
  MkMess_Curr->putendbound = TRUE;

  return TCL_OK;
}

/*
**
**	TCL-command: getfilename
**
**	Return filename of MkMess_Curr
**
*/

int
Mk_GetFilename(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  char *s;
  if (argc != 1) {
    Tcl_AppendResult(interp, "getfilename: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }
  if ((s = (char *)MkMess_Curr->filename) == NULL) 
    Tcl_SetResult(interp, "0", TCL_STATIC);
  else
    Tcl_SetResult(interp, s, TCL_STATIC);
  return TCL_OK;
}

/*
**
**	TCL-command: setfilename "NAME"
**
**	Set filename of MkMess_Curr to "NAME"
**
*/

int
Mk_SetFilename(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  char *s;
  char *p;
  if (argc != 2) {
    Tcl_AppendResult(interp, "setfilename: wrong # args: should be \"", 
		     argv[0], " filename\"", (char *) NULL);
    return TCL_ERROR;
  }
  if ((s = (char *)MkMess_Curr->filename) != NULL) {
    free(MkMess_Curr->filename);
    MkMess_Curr->filename = NULL;
  }
  p = newstr(argv[1]);
  setfilename(p);
  return TCL_OK;
}

/*
**
**	TCL-command: getextension
**
**	Return extension of MkMess_Curr filename
**
*/

int
Mk_GetExtension(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 2) {
    Tcl_AppendResult(interp, "getextension: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }
  if (MkMess_Curr->extension)
    Tcl_SetResult(interp, MkMess_Curr->extension, TCL_STATIC);
  else
    Tcl_SetResult(interp, "0", TCL_STATIC);
  return TCL_OK;
}


/*
**
**	TCL-command: setextension "EXTENSION"
**
**	Set extension to "EXTENSION" of MkMess_Curr filename
**
*/


int
Mk_SetExtension(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 2) {
    Tcl_AppendResult(interp, "setextension: wrong # args: should be \"", 
		     argv[0], "EXTENSION\"", (char *) NULL);
    return TCL_ERROR;
  }
  if (MkMess_Curr->extension != NULL)
    joinextension();
  MkMess_Curr->extension = newstr(argv[1]);
  Tcl_SetResult(interp, "1", TCL_STATIC);
  return TCL_OK;
}

/*
**
**	TCL-command: getbinhextype
**
**	Returns the type bytes of the BinHexed file MkMess_Curr
**
*/

int
Mk_GetBinHexType(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  char s[5];
  if (argc != 1) {
    Tcl_AppendResult(interp, "getbinhextype: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }
  if (MkMess_Curr->binhex == NULL)
    Tcl_SetResult(interp, "0", TCL_STATIC);
  else
    {
      bzero(s,5);
      if (((char *)MkMess_Curr->binhex->btype) == NULL) 
	Tcl_SetResult(interp, "0", TCL_STATIC);
      else {
	strncpy(s, MkMess_Curr->binhex->btype, 4);
	Tcl_SetResult(interp, s, TCL_STATIC);
      }
    }
  return TCL_OK;
}

/*
**
**	TCL-command: setbinhextype "TYPE"
**
**	Sets the 4 type bytes of the BinHexed file MkMess_Curr
**	to "TYPE"
**
*/



int
Mk_SetBinHexType(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 2) {
    Tcl_AppendResult(interp, "setbinhextype: wrong # args: should be \"", 
		     argv[0], " type\"", (char *) NULL);
    return TCL_ERROR;
  }
  if (strlen(argv[1]) != 4)
    {
      Tcl_AppendResult(interp, "setbinhextype: wrong type format:\"",
		       argv[1], "\" should be 4 characters long", 
		       (char *) NULL);
      return TCL_ERROR;
    }
  if (MkMess_Curr->binhex == NULL)
    MkMess_Curr->binhex = (BinHexStruct *)xalloc(sizeof(BinHexStruct));

  strncpy(MkMess_Curr->binhex->btype,argv[1], 4);
  return TCL_OK;
}

/*
**
**	TCL-command: getbinhexauth
**
**	Returns the auth bytes of the BinHexed file MkMess_Curr
**
*/



int
Mk_GetBinHexAuth(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  char s[5];
  if (argc != 1) {
    Tcl_AppendResult(interp, "getbinhexauth: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }
  if (MkMess_Curr->binhex == NULL)
    Tcl_SetResult(interp, "0", TCL_STATIC);
  else
    {
      bzero(s, 5);
      if (((char *)MkMess_Curr->binhex->bauth) == NULL) 
	Tcl_SetResult(interp, "0", TCL_STATIC);
      else {
	strncpy(s, MkMess_Curr->binhex->bauth, 4);
	Tcl_SetResult(interp, s, TCL_STATIC);
      }
    }
  return TCL_OK;
}

/*
**
**	TCL-command: getbinhexauth "AUTH"
**
**	Sets the auth bytes of the BinHexed file MkMess_Curr
**	to "AUTH"
**
*/


int
Mk_SetBinHexAuth(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 2) {
    Tcl_AppendResult(interp, "setbinhexauth: wrong # args: should be \"", 
		     argv[0], " auth\"", (char *) NULL);
    return TCL_ERROR;
  }
  if (strlen(argv[1]) != 4)
    {
      Tcl_AppendResult(interp, "setbinhexauth: wrong auth format: ",
		       argv[1], "\" should be 4 characters long", 
		       (char *) NULL);
      return TCL_ERROR;
    }
  if (MkMess_Curr->binhex == NULL)
    MkMess_Curr->binhex = (BinHexStruct *)xalloc(sizeof(BinHexStruct));

  strncpy(MkMess_Curr->binhex->bauth,argv[1], 4);
  return TCL_OK;
}

/*
**
**	TCL-command: is_set VARIABLE
**
**	Returns TRUE if the variable VARIABLE is set
**
*/

int
Mk_IsSet(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  int i;
  char *result;
  if (argc < 2) {
    Tcl_AppendResult(interp, "is_set: wrong # args: should be \"", argv[0], 
		     "Variable [Variable]*\"", (char *) NULL);
    return TCL_ERROR;
  }

  for (i = 1; i < argc; i++) {
    result = (char *)Tcl_GetVar(interp, argv[i], 0);
    if (result == NULL) {
      Tcl_SetResult(interp, "0", TCL_STATIC);
      return TCL_OK;
    }
  }
  Tcl_SetResult(interp, "1", TCL_STATIC);
  return TCL_OK;
}


int
Mk_IsRoot(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc < 1) {
    Tcl_AppendResult(interp, "is_root: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }

  if (MkMess_Curr != MkMess_Root)
    Tcl_SetResult(interp, "0", TCL_STATIC);
  else
    Tcl_SetResult(interp, "1", TCL_STATIC);
  return TCL_OK;
}

/*
**
**	TCL-command: is_multipart
**
**	Returns TRUE if message is of type MULTIPART, ie
**	has more than one bodypart.
**
*/

int
Mk_IsMulti(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc < 1) {
    Tcl_AppendResult(interp, "is_root: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }

  if (MkMess_Root->ismulti)
    Tcl_SetResult(interp, "1", TCL_STATIC);
  else
    Tcl_SetResult(interp, "0", TCL_STATIC);
  return TCL_OK;
}

/*
**
**	TCL-command: setencoding "ENCODING"
**
**	Sets the encoding string of MkMess_Curr to "ENCODING".
**
*/


int
Mk_SetEncoding(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  TypeStruct *encodings;
  if (argc != 2) 
    Tcl_AppendResult(interp, "setencoding: wrong # args: should be \"", 
		     argv[0], " encoding\"", (char *) NULL);
  for (encodings = MkEncodings; encodings->name != NULL; encodings++) 
    if (!strcasecmp(argv[1], encodings->name))
      break;
  if (encodings->name)
    MkMess_Curr->encoding = newstr(encodings->name);
  MkMess_Curr->enc = encodings->type;
  return TCL_OK;
}

/*
**
**	TCL-command: dosubheaders
**
**	This mailer wants subheaders, ie MIME or SUN mailtool etc.
**
*/

int
Mk_DoSubHeaders(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 1) {
    Tcl_AppendResult(interp, "dosubheaders: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }
  MkMess_Root->dosubheaders = TRUE;
  return TCL_OK;
}

/*
**
**	TCL-command: dotunnel
**
**	Set Emil to transparant mode. No conversions.
**
*/

int
Mk_DoTunnel(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  if (argc != 1) {
    Tcl_AppendResult(interp, "dotunnel: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }
  MkMess_Root->dotunnel = TRUE;
  return TCL_OK;
}

/*
**
**	TCL-command: gethighchars
**
**	Returns the number of high characters (>127) in MkMess_Curr.
**
*/

int
Mk_GetHighChars(clientData, interp, argc, argv)
    ClientData clientData;
    Tcl_Interp *interp;
    int argc;
    char *argv[];
{
  char t[20];

  if (argc != 1) {
    Tcl_AppendResult(interp, "gethighchars: wrong # args: should be \"", 
		     argv[0], "\"", (char *) NULL);
    return TCL_ERROR;
  }
  sprintf(t, "%i", MkMess_Curr->highchars);
  
  Tcl_SetResult(interp, t, TCL_STATIC);
  return TCL_OK;
}



