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


/*
 *
 */


/*
 * void
 * encode_header()
 *
 */

void
encode_header(struct message *m)
{
  switch(target->iformat)
    {
    case MIME:
      encode_mime(m);
      break;
    case MAILTOOL:
      encode_mailtool(m);
      break;
    default:
      encode_rfc822(m);
      break;
    }
}
	  

/*
 * void 
 * decode_header()
 *
 * Parses the header of current message.
 */
void
decode_header(struct message *m)
{
  struct data *d;
  d = m->sd;
  if (m->h == NULL)
    {
      logger(LOG_DEBUG, "decode_header: empty header");
      return;
    }

  /**
   ** m->level 0 specifics
   **/

  if (m->level == 0) 
    {

      if (matchheader(m, "Content-Conversion", "Prohibited", 0))
	{
#ifdef DEBUG
	  if (edebug)
	    fprintf(stderr, "Content conversion prohibited.\n");
#endif
	  det_sket_sig = TRUE;
	  return;
	}
    }
  if (decode_mime(m) != OK)
    {
      if (decode_mailtool(m) != OK)
	{
	  decode_rfc822(m);
	}
    }
}


/*
 * char *
 * fixstring(STRING, BEFORE, AFTER, PROCESS)
 *
 * Process STRING according to PROCESS (UNQUOTE, UNSPACE) and return
 * the merged BEFORE, STRING and AFTER.
 */
char *
fixstring(char *string, char *before, char *after, short process)
{
  char *tmp1, *tmp2;
  int slen, blen, alen;
  if (string == NULL)
    return(NULL);
  if (*string != '\0' && (process & UNSPACE))
    {
      tmp1 = string;
      while(*tmp1 == ' ' || *tmp1 == '\t')
	tmp1++;
      if (*tmp1 != '\0')
	{
	  tmp2 = tmp1 + strlen(tmp1) - 1;
	  while (*tmp2 == ' ' || *tmp2 == '\t')
	    tmp2--;
	  tmp2++;
	  *tmp2 = '\0';
	}
      string = tmp1;
    }
  if (*string != '\0' && (process & UNQUOTE) )
    {
      tmp1 = string;
      if (*tmp1 == '"')
	{
	  tmp1++;
	  tmp2 = string + strlen(string) - 1;
	  if (*tmp2 == '"')
	    {
	      *tmp2 = '\0';
	      string = tmp1;
	    }
	}
    }
  if (*string != '\0')
    slen = strlen(string);
  else
    slen = 0;
  if (before != NULL && *before != '\0')
    blen = strlen(before);
  else
    blen = 0;
  if (after != NULL && *after != '\0')
    alen = strlen(after);
  else
    alen = 0;
  tmp1 = (char *)Yalloc(blen + slen + alen + 1);
  if (blen)
    strcpy(tmp1, before);
  if (slen)
    strcat(tmp1, string);
  if (alen)
    strcat(tmp1, after);
  return(tmp1);
}


/*
 * bool
 * matchheader(HFIELD, HVAL)
 *
 * If header HFIELD is available, matches HVAL against the value
 * of the header. Returns TRUE on success and FALSE on failure.
 */
int
matchheader(struct message *m, char *hfield, char *hval, int format)
{
  struct header *hdr;
  if (hfield == NULL || hval == NULL)
    return(FALSE);
  for (hdr = m->h; hdr != NULL; hdr = hdr->next)
    {
      if (hdr->type != UNIXFROM && hdr->field->end != 0 && 
	  (cmatch(hdr->field->contents, hfield) == TRUE))
	{
	  if (matchhvalue(hdr, hval))
/*	  if (hdr->value->end != 0 && 
	      (cmatch(hdr->value->contents, hval) == TRUE))
*/
	    {
#ifdef DEBUG
	      if (edebug)
		fprintf(stderr, "*   matchhvalue success\n");
#endif
	      hdr->format = format;
	      return(TRUE);
	    }
	  else
	    {
#ifdef DEBUG
	      if (edebug)
		fprintf(stderr, "*   matchhvalue failed\n");
#endif
	      return(FALSE);
	    }
	}
      
    }
  return(FALSE);
}

int
matchhvalue(struct header *hdr, char *line)
{
  static struct header *th = NULL;

  if (th == NULL)
    {
      th = (struct header *)Yalloc(sizeof(struct header));
      th->field = (struct data *)Yalloc(sizeof(struct data));
      th->value = (struct data *)Yalloc(sizeof(struct data));
    }
  else
    {
      th->field->end = 0;
      th->value->end = 0;
      th->value->offset = 0;
      th->hvalue = NULL;
    }
  append_data(th->field, hdr->field->contents, strlen(hdr->field->contents),
	      256);
  append_data(th->value, line, strlen(line),
	      256);
#ifdef DEBUG  
  if (edebug)
    fprintf(stderr, "*   matchhvalue: %s: matching %s with %s\n",
	    hdr->field->contents,
	    hdr->value->contents,
	    line);
#endif
  if (parse_rfc1522(th) != OK)
    return(0);
  return(compare_header(hdr->hvalue, th->hvalue));
}

int
compare_header(struct hprs *dirty, struct hprs *clean)
{
  if (clean == NULL && dirty == NULL)
    return(1);
  if (clean == NULL || clean->type != DELIMITER)
    {
      while(dirty != NULL && dirty->type == DELIMITER)
	dirty = dirty->sibling;
      if (dirty == NULL)
	{
	  if (clean == NULL)
	    return(1);
	  else
	    {
#ifdef DEBUG
	      if (edebug)
		fprintf(stderr, "*   compare_header: dirty unexpected end\n");
#endif
	      return(0);
	    }
	}
    }
  while(dirty->type == COMMENT)
    dirty = dirty->sibling;

#ifdef DEBUG
  if (edebug)
    fprintf(stderr, "*   compare_header: trying match between %d and %d\n",
	    dirty->type, clean->type);
#endif
  switch (clean->type)
    {
    case UNKNOWN:
      if (dirty->type != UNKNOWN)
	{
#ifdef DEBUG
	  if (edebug)
	    fprintf(stderr, "*   compare_header: clean type is UNKNOWN\n");
#endif
	  return(0);
	}
      break;
    case COMMENT:
      break;
    case HQSTRING:
      if (dirty->type != HQSTRING)
	{
#ifdef DEBUG
	  if (edebug)
	    fprintf(stderr, "*   compare_header: expecting COMMENT got %d\n", 
		    dirty->type);
#endif
	  return(0);
	}
      break;
    case DLITERAL:
      if (dirty->type != DLITERAL)
	{
#ifdef DEBUG
	  if (edebug)
	    fprintf(stderr, "*   compare_header: expecting DLITERAL got %d\n",
		    dirty->type);
#endif
	  return(0);
	}
      break;
    case RADDR:
      if (dirty->type != RADDR)
	{
#ifdef DEBUG
	  if (edebug)
	    fprintf(stderr, "*   compare_header: expecting RADDR got %d\n",
		    dirty->type);
#endif
	  return(0);
	}
      break;
    case RFC1522: 
      if (dirty->type != RFC1522)
	{
#ifdef DEBUG
	  if (edebug)
	    fprintf(stderr, "*   compare_header: expecting RFC1522 got %d\n",
		    dirty->type);
#endif
	  return(0);
	}
      break;
    case ATOM:
      if (dirty->type != ATOM)
	{
#ifdef DEBUG
	  if (edebug)
	    fprintf(stderr, "*   compare_header: expecting ATOM got %d\n",
		    dirty->type);
#endif
	  return(0);
	}
      if (dmatch(clean->sd, dirty->sd) == 0)
	  return(0);
      break;
    case DELIMITER:
      if (dirty->type != DELIMITER)
	{
#ifdef DEBUG
	  if (edebug)
	    fprintf(stderr, "*   compare_header: expecting DELIMITER got %d\n",
		    dirty->type);
#endif
	  return(0);
	}
      break;
    case TEXT:
      if (dirty->type != TEXT)
	{
#ifdef DEBUG
	  if (edebug)
	    fprintf(stderr, "*   compare_header: expecting TEXT got %d\n",
		    dirty->type);
#endif
	  return(0);
	}
      clean = clean->child;
      dirty = dirty->child;
      return(compare_header(dirty, clean));
      break;
    default:
      break;
    }
  clean = clean->sibling;
  dirty = dirty->sibling;
  return(compare_header(dirty, clean));
}

int
dmatch(struct data *a, struct data *b)
{
  int alen, blen;
  alen = a->bodyend - a->bodystart;
  blen = b->bodyend - b->bodystart;
  if (alen != blen)
    {
#ifdef DEBUG
      if (edebug)
	{
	  fprintf(stderr, "*   dmatch: lengths differ: %d %d\n",
		  alen, blen);
	  fprintf(stderr, "*   dmatch: tried to compare %s and %s\n",
		a->contents, b->contents);
	}      
#endif
      return(0);
    }
  if (strncasecmp(a->contents + a->bodystart, b->contents + b->bodystart, alen) != 0)
    {
#ifdef DEBUG
      if (edebug)
	fprintf(stderr, "*   dmatch: %s and %s does not match\n",
		a->contents, b->contents);
#endif
      return(0);
    }
  return(1);
}
/*
 * char *
 * gethval(HFIELD)
 *
 * If header HFIELD is available, returns the corresponding value
 * as a string. Returns NULL on failure.
 */

char *
gethval(struct message *m, char *hfield, int format)
{
  struct header *hdr;
  if (hfield == NULL)
    return(NULL);
  for (hdr = m->h; hdr != NULL; hdr = hdr->next)
    {
      if (hdr->type != UNIXFROM && hdr->field->end != 0 && 
	  cmatch(hdr->field->contents, hfield) == TRUE)
	{
	  if (format)
	    hdr->format = format;
	  return(hdr->value->contents);
	}
    }
  return(NULL);
}

/*
 * int
 * string2dec(STRING)
 *
 * If STRING is not NULL and not of m->length zero and consists of 0-9, 
 * returns the translation to an integer. Returns 0 on failure.
 */
int
string2dec(char *string)
{
  if (string == NULL)
    return(0);
  return((int)atol(string));
}

/*
 * char *
 * stringpart(STRING, DEL, PARTNO)
 *
 * Delimits STRING by DEL and returns part number PARTNO, where
 * parts start with zero for the first part and so on. Returns
 * NULL on failure.
 */
char *
stringpart(char *string, char *del, int partno)
{
  char *str, *start;
  int slen;
  int i = 0;
  if (string == NULL || del == NULL)
    return(string);
  slen = strlen(string);
  str = (char *)NEWSTR(string);
  start = str;
  /* Loop on string */
  while (1)
    {
      /* Delimit string */
      while (*str != '\0' && index(del, *str) == NULL)
	{
	  str++;
	  slen--;
	}
      *str = '\0';
      if (i == partno)
	return(start);
      else
	{
	  if (!slen)
	    break;
	  str++;
	  slen--;
	  start = str;
	}
      i++;
    }
  return(NULL);
}
/*
 * bool
 * matchpart(STRING1, STRING2, DEL, PARTNO)
 *
 * Delimits STRING2 by DEL and and matches part number PARTNO with
 * STRING1. Returns TRUE on success and FALSE on failure.
 */
int
matchpart(char *string1, char *string2, char *del, int partno)
{
  char *str, *start;
  int i = 0;
  if (string1 == NULL || string2 == NULL || del == NULL)
    return(FALSE);
  str = NEWSTR(string1);
  start = str;
  for (; str != '\0' && i <= partno; str++)
    {
      if (index(del, *str) != NULL)
	{
	  *str = '\0';
	  if (i == partno && cmatch(start, string2) == TRUE)
	    {
	      return(TRUE);
	    }
	  else
	    {
	      str++;
	      start = str;
	    }
	  i++;
	}
    }
  return(FALSE);
}
/*
 * char *
 * getpartrest(STRING, MATCH, DEL)
 *
 * Delimits STRING by DEL and tries MATCH on every part returns the
 * unmatched part of the part matched.
 */
char *
getpartrest(char *string, char *matchstr, char *del)
{
  char *str, *start;
  int mlen, slen;
#ifdef DEBUG
  if (edebug)
  fprintf(stderr, "\ngetpartrest: string: %s matchstr: %s, del: %s\n",
	  string, matchstr, del);
#endif
  if (string == NULL || matchstr == NULL || del == NULL)
    return(NULL);
  if ((mlen = strlen(matchstr)) == 0 || (slen = strlen(string)) == 0)
    return(NULL);
  str = (char *)NEWSTR(string);
  start = str;
  while (1)
    {
      /* Delimit string */
      if (!slen)
	return(NULL);
      
      while (*str != '\0' && *del !=  *str)
	{
	  str++;
	  slen--;
	  if (!slen)
	    break;
	}
      *str = '\0';
      while (isspace(*start))
	start++;
      if (strncasecmp(matchstr, start, mlen) == 0)
	return(start + mlen);
      else
	{
	  if (!slen)
	    break;
	  str++;
	  slen--;
	  start = str;
	}
    }
  return(NULL);
}

/*
 * int
 * match(string1, string2)
 * 
 * Case sensitive match
 */
int
match(char *string1, char *string2)
{
  if (string1 == NULL || string2 == NULL)
    return(FALSE);
  if (strcmp(string1, string2) == 0)
    return(TRUE);
  else
    return(FALSE);
}


/*
 * int
 * cmatch(string1, string2)
 * 
 * Case insensitive match
 */
int
cmatch(char *string1, char *string2)
{
  if (string1 == NULL || string2 == NULL)
    return(FALSE);
  if (strcasecmp(string1, string2) == 0)
    return(TRUE);
  else
    return(FALSE);
}

	  
	

