/*
**
** 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 "config.h"

/*
 * ifdefs, used for portability
 */

#define	EMIL_VERSION	"2.0.2"

#if STDC_HEADERS || HAVE_STRING_H
#include <string.h>
/* An ANSI string.h and pre-ANSI memory.h might conflict */
#if !STDC_HEADERS && HAVE_MEMORY_H
#include <memory.h>
#endif /* not STDC_HEADERS && HAVE_MEMORY_H */
#ifndef	RINDEX_DEFINED
#define index strchr
#define rindex strrchr
#endif
#define bcopy(s, d, n) memcpy((d), (s), (n))
#define bcmp(s1, s2, n) memcmp((s1), (s2), (n))
#define bzero(s, n) memset((s), 0, (n))
#else /* not STDC_HEADERS and not HAVE_STRING_H */
#include <strings.h>
/* memory.h and strings.h conflict on some systems */
#endif /* not STDC_HEADERS and not HAVE_STRING_H */

#ifdef HAVE_SYSEXITS_H
#include <sysexits.h>
#else
#define EX_OK     0
#define EX_OSERR 71
#endif

#ifndef	__P
#if defined(__STDC__)
#define __P(protos) protos   /* Full-blown ANSI C */
#else
#define __P(protos) ()       /* Traditional C preprocessor */
#endif /* !__STDC__ */
#endif




/*
 * Standard includes
 */
#include <stdio.h>
#include <sys/types.h>
#include <syslog.h>
#include <stdlib.h>
#include <ctype.h> 
#ifdef	HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <assert.h>
#include <fcntl.h>
  
/*
 * C function definitions
*/

#ifndef	STRCASECMP_DEFINED
int	strcasecmp(char *, char *);
#endif
#ifndef	STRNCASECMP_DEFINED
int	strncasecmp(char *, char *, int);
#endif


/*
 * Message Structure 
 */

struct message {
  struct header *h;
  struct data *sd;
  struct data *td;
  char *type;
  char *name;
  char appletype[9];
  char *nameext;
  char *description;
  int level;
  struct message *sibling;
  struct message *child;
  struct message *bigsib;
  struct message *parent;
  struct config_struct * c;
};

struct info {
};
/*
 * Header structure
 */


#define UNIXFROM 1 /* Unix from line flag */
#define HEADER   2 /* Regular header line flag */

struct header {
  int type;        /* Unix from line or regular header */
  int format;      /* RFC822, MIME or MAILTOOL */
  struct data *field;     /* Field  */
  struct data *value;     /* Value */
  struct hprs *hvalue;
  struct header *next;
};

struct hprs {
  int encoding;
  int type;
  int types;
  int pstart;
  int pend;
  char *charset;
  struct data *sd;
  struct data *td;
  struct hprs *sibling;
  struct hprs *child;
};

/*
 * Data structure
 */

struct data {
  char *charset;   /* Charset */
  char *startbound;/* Start boundary */
  char *endbound;  /* End boundary */
  int length;      /* Predefined bodypart length */
  int bodylines;   /* Some predefined number of bodylines in the part */
  int format;      /* Main format of the message */
  int encoding;    /* E7BIT, EBINHEX, EUUENCODE, EBASE64, EQP or EMULTIPART */
  int check;       /* Check for these encodings */
  long end;        /* End of defined data */
  long size;       /* Size of data area */
  long bodystart;  /* Start of bodypart data */
  long bodyend;    /* End of bodypart data */
  long offset;     /* Current position in data area */
  long linestart;  /* Linecount at start of body part */
  long lineend;    /* Linecount at end of bodypart */
  long loffset;    /* Current linecount */
  long lend;       /* Linecount of end of defined data */
  char *contents;  /* Pointer to data area */
};

/*
 * Indata structure
 */

struct indata {
  void (*input_function)();
  int l;
  int offset;
  char *data;
};

/*
 * Configuration parameters
*/

struct	config_struct {
	struct	config_struct * gg;
	char	* name,
		* charset,
		* format,
 	        * text,
                * header,
		* bin;
	int     iformat,
	        ibin,
	        itext,
	        htext;
};

/*
 * Macros
 */

#define APPEND_LINE(L1, L2) strcat(L1, L2)
#define NEWSTR(S) strcpy((char *)Yalloc(strlen(S) + 1), S)


/*
 * Defines
 */

/* General status */
#define OK 0
#define NOK -1
#define TRUE 1
#define FALSE 0
#define FAIL -1
#define SKIP -2
#define DONE -3

/* Used for delimiter matches */
#define ESTRIP    0x000
#define E7BIT     0x001
#define EBINHEX   0x002
#define EUUENCODE 0x004
#define EMULTI    0x008
#define EBASE64   0x010
#define EQP       0x020
#define EBINARY   0x040
#define EHQX      0x080
#define EASING    0x100
#define EADOUB    0x200
#define E8BIT     0x400
#define ESE       0x800
/* Main types */
#define RFC822 0      /* Default */
#define MIME 1
#define MAILTOOL 2

/*
 * Sizes
 */

#define HDRLEN 2048
#define LINELEN 1024
#define MIMEBOUNDLEN 60

/* Pseudos */
#define UNQUOTE 1
#define UNSPACE 2

/* File types */
#define TYPEUNKNOWN 0
#define TYPEAPPLEDOUBLE 1
#define TYPEAPPLESINGLE 2

/* Header fields */
#define UNKNOWN    0
#define COMMENT    1
#define HQSTRING   2
#define DLITERAL   4
#define RADDR      8
#define RFC1522   16
#define ATOM      32
#define DELIMITER 64
#define TEXT     128
#define TOP      256
/*
 * Externals
 */
extern char ebuf[1024];
extern char *sender;
extern char *recipient;
extern short det_sket_sig;
extern struct body *currbody;
extern struct message *rootmess;
extern struct config_struct *source;
extern struct config_struct *target;
extern int process;
#ifdef DEBUG
extern int edebug;
#endif

#ifdef	hpux
/* pagesize if a bit uncertain */
#define	getpagesize()	4096
#else
#ifdef	aix
size_t	getpagesize();	/* Should really be in unistd.h */
#endif
#endif

/*
 * Function prototypes 
*/


void    * Yalloc(int);		/* block, zero */
int     tocharset(struct message *);
char    * confextr(char *, char *, char *);
struct  config_struct   * getoption(char *, char *, char *);

int     recode_data(struct message *);
int     decode_binhex(struct message *);
int     decode_uuencode(struct message *);
int     decode_base64(struct message *);
int     decode_quoted_printable(struct message *);

void    encode_header(struct message *);
int     encode_binhex(struct message *);
int     encode_uuencode(struct message *);
int     encode_base64(struct message *);
int     encode_quoted_printable(struct message *);

void    add_header(struct message *, char *, char *, int);
int     isheader(char *);
int     getline(struct data *);

struct  data    * load_data(void);
int     parse_message(struct message *);
int	convert_data(struct message *);
void    out_message(struct message *);
void fix_filename(struct message *);

void    print_config(struct config_struct *);
void    print_data(struct data *);
int     load_header(struct message *);
void    decode_header(struct message *);
int	matchheader(struct message *, char *, char *, int);
int	match(char *, char *);
int     cmatch(char *, char *);
char 	* gethval(struct message *, char *, int);
int	string2dec(char *);
char	* stringpart(char *, char*, int);
void	print_body(struct data *); /* forward */
char    * getextension(char *);


unsigned long calc_crc(unsigned long crc, unsigned int);
int	get_binhex_namelen(struct data *);
int	get_binhex_name(struct data *);
int	get_binhex_type(struct data *);
int	get_binhex_auth(struct data *);
int	get_binhex_flags(struct data *);
int	get_binhex_dlen(struct data *);
int	get_binhex_rlen(struct data *);
int	get_binhex_crc(struct data *, unsigned long);
int	get_binhex_datafork(struct data *);
int	get_binhex_resourcefork(struct data *);
int	get_file_type(struct data *);
int	get_binhex_binary(struct message *);
int	create_binhex_binary(struct message *);

int	append_char(struct data *, char);
int	append_data(struct data *, char *, int);

void	encode_mime(struct message *);
int	decode_mime(struct message *);
void    encode_rfc822(struct message *);
int     decode_rfc822(struct message *);
void	encode_mailtool(struct message *);
int	decode_mailtool(struct message *);

void	print_header(struct header *);
void	print_mstruct(struct message *);

char	* fixstring(char *, char *, char *, short);
char	* getpartrest(char *, char *, char *);

void	logger(int level, char * format);

