/*-----------------------------------------------------------------------
  **
  **
  ** MIME_headers
  **
  ** Written by Paul L Daniels, originally for the Xamime project
  ** (http://www.xamime.com) but since spawned off to the ripMIME/alterMIME
  ** family of email parsing tools.
  **
  ** Copyright PLD, 1999,2000,2001,2002,2003
  ** Licence: BSD
  ** For more information on the licence and copyrights of this code, please
  **	email copyright@pldaniels.com

  ** CHANGES
  ** 2003-Jun-24: PLD: Added subject parsing
  **

  */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>


#include "ffget.h"
#include "pldstr.h"
#include "libmime-decoders.h"
#include "logger.h"
#include "MIME_headers.h"


#ifndef FL
#define FL __FILE__, __LINE__
#endif

// Debug precodes
#define MIMEH_DPEDANTIC ((glb.debug >= _MIMEH_DEBUG_PEDANTIC))
#define MIMEH_DNORMAL   ((glb.debug >= _MIMEH_DEBUG_NORMAL  ))




struct MIMEH_globals {

	int doubleCR;
	int doubleCR_save;
	char doubleCRname[_MIMEH_STRLEN_MAX +1];

	char appledouble_filename[_MIMEH_STRLEN_MAX +1];

	char *headerline;
	char *headerline_original;	// Holds the original header-form without decoding.
	int save_headers;
	int save_headers_original;
	int test_mailbox;
	int debug;
	int webform;
	int doubleCR_count;
	int verbose;
	int verbose_contenttype;
	char output_dir[_MIMEH_STRLEN_MAX +1];

	FILE *header_file;
};

static struct MIMEH_globals glb;



/*-----------------------------------------------------------------\
 Function Name	: MIMEH_version
 Returns Type	: int
 	----Parameter List
	1. void, 
 	------------------
 Exit Codes	: 
 Side Effects	: 
--------------------------------------------------------------------
 Comments:
 
--------------------------------------------------------------------
 Changes:
 
\------------------------------------------------------------------*/
int MIMEH_version(void)
{
	fprintf(stdout,"mimeheaders: %s\n", MIMEH_VERSION);

	return 0;
}

/*-----------------------------------------------------------------\
  Function Name	: MIMEH_init
  Returns Type	: int
  ----Parameter List
  1. void , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_init( void )
{
	glb.doubleCR = 0;
	glb.headerline = NULL;
	glb.headerline_original = NULL;
	glb.save_headers = 0;
	glb.save_headers_original = 0;
	glb.test_mailbox = 0;
	glb.debug = 0;
	glb.webform = 0;
	glb.doubleCR_count = 0;
	glb.doubleCR_save = 1;
	glb.verbose = 0;
	glb.verbose_contenttype = 0;
	glb.output_dir[0]='\0';
	glb.doubleCRname[0]='\0';
	glb.appledouble_filename[0]='\0';

	return 0;
}

/*-----------------------------------------------------------------\
  Function Name	: MIMEH_get_doubleCR
  Returns Type	: int
  ----Parameter List
  1. void , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_get_doubleCR( void )
{
	return glb.doubleCR;
}

/*-----------------------------------------------------------------\
  Function Name	: MIMEH_set_doubleCR
  Returns Type	: int
  ----Parameter List
  1. int level , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_set_doubleCR( int level )
{
	glb.doubleCR = level;

	return glb.doubleCR;
}

/*-----------------------------------------------------------------\
 Function Name	: MIMEH_set_doubleCR_save
 Returns Type	: int
 	----Parameter List
	1. int level , 
 	------------------
 Exit Codes	: 
 Side Effects	: 
--------------------------------------------------------------------
 Comments:
 
--------------------------------------------------------------------
 Changes:
 
\------------------------------------------------------------------*/
int MIMEH_set_doubleCR_save( int level )
{
	glb.doubleCR_save = level;

	return glb.doubleCR_save;
}

/*-----------------------------------------------------------------\
 Function Name	: MIMEH_get_doubleCR_save
 Returns Type	: int
 	----Parameter List
	1. void , 
 	------------------
 Exit Codes	: 
 Side Effects	: 
--------------------------------------------------------------------
 Comments:
 
--------------------------------------------------------------------
 Changes:
 
\------------------------------------------------------------------*/
int MIMEH_get_doubleCR_save( void )
{
	return glb.doubleCR_save;
}


/*-----------------------------------------------------------------\
  Function Name	: *MIMEH_get_doubleCR_name
  Returns Type	: char
  ----Parameter List
  1. void , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
char *MIMEH_get_doubleCR_name( void )
{
	return glb.doubleCRname;
}


/*-----------------------------------------------------------------\
  Function Name	: MIMEH_set_debug
  Returns Type	: int
  ----Parameter List
  1. int level , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_set_debug( int level )
{
	glb.debug = level;
	return glb.debug;
}

/*-----------------------------------------------------------------\
  Function Name	: MIMEH_set_outputdir
  Returns Type	: int
  ----Parameter List
  1. char *dir , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_set_outputdir( char *dir )
{
	if (dir) snprintf(glb.output_dir,_MIMEH_STRLEN_MAX,"%s",dir);
	return 0;
}

/*-----------------------------------------------------------------\
  Function Name	: MIMEH_set_webform
  Returns Type	: int
  ----Parameter List
  1. int level , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_set_webform( int level )
{
	glb.webform = level;
	return glb.webform;
}


/*-----------------------------------------------------------------\
  Function Name	: MIMEH_set_mailbox
  Returns Type	: int
  ----Parameter List
  1. int level , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_set_mailbox( int level )
{
	glb.test_mailbox = level;
	return level;
}

/*-----------------------------------------------------------------\
  Function Name	: MIMEH_set_verbosity
  Returns Type	: int
  ----Parameter List
  1. int level , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_set_verbosity( int level )
{
	glb.verbose = level;
	return level;
}

/*-----------------------------------------------------------------\
  Function Name	: MIMEH_set_verbosity_contenttype
  Returns Type	: int
  ----Parameter List
  1. int level , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_set_verbosity_contenttype( int level )
{
	glb.verbose_contenttype = level;
	return level;
}

/*-----------------------------------------------------------------\
  Function Name	: MIMEH_get_verbosity_contenttype
  Returns Type	: int
  ----Parameter List
  1. void , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_get_verbosity_contenttype( void )
{
	return glb.verbose_contenttype;
}



/*------------------------------------------------------------------------
Procedure:     MIMEH_set_headers_save ID:1
Purpose:       Sets MIMEH's headers save file (where MIMEH will save the
headers it reads in from the mailpack)
Input:
Output:
Errors:
------------------------------------------------------------------------*/
int MIMEH_set_headers_save( FILE *f )
{
	glb.header_file = f;
	glb.save_headers = 1;
	return 0;
}

/*-----------------------------------------------------------------\
  Function Name	: MIMEH_set_headers_nosave
  Returns Type	: int
  ----Parameter List
  1. void , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_set_headers_nosave( void )
{
	glb.header_file = NULL;
	glb.save_headers = 0;
	return 0;
}

/*-----------------------------------------------------------------\
  Function Name	: MIMEH_get_headers_save
  Returns Type	: int
  ----Parameter List
  1. void , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_get_headers_save( void )
{
	return glb.save_headers;
}


/*-----------------------------------------------------------------\
  Function Name	: MIMEH_set_headers_save_original
  Returns Type	: int
  ----Parameter List
  1. int level , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_set_headers_save_original( int level )
{
	glb.save_headers_original = level;

	return glb.save_headers_original;
}


/*-----------------------------------------------------------------\
  Function Name	: MIMEH_get_headers_ptr
  Returns Type	: int
  ----Parameter List
  1. void , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
char *MIMEH_get_headers_ptr( void )
{
	return glb.headerline;
}


/*-----------------------------------------------------------------\
  Function Name	: *MIMEH_get_headers_original_ptr
  Returns Type	: char
  ----Parameter List
  1. void , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
char *MIMEH_get_headers_original_ptr( void )
{
	return glb.headerline_original;
}



/*-----------------------------------------------------------------\
  Function Name	: MIMEH_is_contenttype
  Returns Type	: int
  ----Parameter List
  1. int range_type, 
  2.  int content_type , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_is_contenttype( int range_type, int content_type )
{
	int diff;

	diff = content_type -range_type;

	if ((diff < _CTYPE_RANGE)&&(diff > 0)) return 1;
	else return 0;
}


/*-----------------------------------------------------------------\
 Function Name	: MIMEH_is_binary
 Returns Type	: int
 	----Parameter List
	1. struct FFGET_FILE *f , 
 	------------------
 Exit Codes	: 1 = yes, it's binary, 0 = no.
 Side Effects	: 
--------------------------------------------------------------------
 Comments:
 
--------------------------------------------------------------------
 Changes:
 
\------------------------------------------------------------------*/
int MIMEH_is_binary( char *fname )
{
	char buffer[1024];
	int read_count;
	FILE *f;

	f = fopen(fname,"r");
	if (!f) return 1;
	read_count = fread(buffer, 1, 1024, f);
	fclose(f);
	
	while (read_count)
	{
		read_count--;
		if (buffer[read_count] == 0) return 1;
	}

	return 0;
}

/*-----------------------------------------------------------------\
  Function Name	: MIMEH_save_doubleCR
  Returns Type	: int
  ----Parameter List
  1. FFGET_FILE *f , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_save_doubleCR( FFGET_FILE *f )
{
	char c;
	FILE *fo;
	struct stat st;


	// Determine a file name we can use.

	do {
		glb.doubleCR_count++;
		snprintf(glb.doubleCRname,_MIMEH_STRLEN_MAX,"%s/doubleCR.%d",glb.output_dir,glb.doubleCR_count);
	}
	while (stat(glb.doubleCRname, &st) == 0);


	fo = fopen(glb.doubleCRname,"w");
	if (!fo)
	{
		LOGGER_log("%s:%d:MIMEH_save_doubleCR:ERROR: unable to open '%s' to write (%s)", FL,glb.doubleCRname,strerror(errno));
		return -1;
	}

	if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIME_save_doubleCR:DEBUG: Saving DoubleCR header: %s\n", FL,glb.doubleCRname);

	while (1)
	{
		c = FFGET_fgetc(f);
		fprintf(fo,"%c",c);
		
		if ((c == EOF)||(c == '\n'))
		{
			break;
		}
	}

	fclose(fo);

	return 0;
}


/*------------------------------------------------------------------------
Procedure:     MIMEH_read_headers ID:1
Purpose:       Reads from the stream F until it detects a From line, or a blank line
(end of headers)
Input:
Output:
Errors:
------------------------------------------------------------------------*/
int MIMEH_read_headers( FFGET_FILE *f )
{
	char buffer[_MIMEH_STRLEN_MAX+1];
	int totalsize=0;
	int linesize=0;
	int totalsize_original=0;
	int result = 0;
	int firstline = 1;
	char *tmp;
	char *tmp_original;
	char *fget_result = NULL;
	char *headerline_end;
	char *p;
	char *linestart;

	glb.headerline = NULL;
	glb.headerline_original = NULL;
	tmp_original = NULL;


	while ((fget_result=FFGET_fgets(buffer,_MIMEH_STRLEN_MAX, f)))
	{

		linestart = buffer;
		linesize = strlen(linestart);
		if (MIMEH_DNORMAL)LOGGER_log("%s:%d:MIMEH_read_headers: Data In=[sz=%d:tb=%d]'%s'",FL, linesize, f->trueblank, buffer);

		// if we are being told to keep a copy of the original data
		//	as it comes in from ffget, then do the storage here
		if (glb.save_headers_original > 0)
		{
			//LOGGER_log("DEBUG:Data-In:[%d:%d] '%s'", strlen(linestart), linesize, linestart);
			tmp_original = realloc(glb.headerline_original, totalsize_original+linesize+1);
			if (tmp_original == NULL)
			{
				LOGGER_log("%s:%d:MIMEH_read_headers:ERROR: Cannot allocate %d bytes to contain new headers_original ", FL,totalsize_original +linesize +1);
				if (glb.headerline_original != NULL) free(glb.headerline_original);
				glb.headerline_original = NULL;
				return -1;
			}

			if (glb.headerline_original == NULL)
			{
				glb.headerline_original = tmp_original;
				totalsize_original = linesize +1;
				PLD_strncpy( glb.headerline_original, linestart, (linesize+1));
				//LOGGER_log("DEBUG: '%s'", glb.headerline_original);
			} else {
				glb.headerline_original = tmp_original;
				PLD_strncpy( (glb.headerline_original +totalsize_original -1), linestart, (linesize +1));
				totalsize_original += linesize;
				//LOGGER_log("DEBUG: '%s'", glb.headerline_original);
			}
			//LOGGER_log("DEBUG:linesize=%d data='%s'",linesize, linestart);
		}


		// Normal processing of the headers now starts.
		tmp = realloc(glb.headerline, totalsize+linesize+1);
		if (tmp == NULL)
		{
			LOGGER_log("%s:%d:MIMEH_read_headers:ERROR: Cannot allocate %d bytes to contain new headers ", FL,totalsize +linesize +1);
			if (glb.headerline != NULL) free(glb.headerline);
			glb.headerline = NULL;
			return -1;
		}

		if (glb.headerline == NULL)
		{
			glb.headerline = tmp;
			totalsize = linesize;
			PLD_strncpy(glb.headerline, linestart, (linesize +1));
			headerline_end = glb.headerline +totalsize;
		} // If the global headerline is currently NULL
		else
		{

			// Perform header unfolding by removing any CRLF's
			//	of the last line if the first characters of the
			//	newline are blank/space

			glb.headerline = tmp;

			if ((*linestart == '\t')||(*linestart == ' '))
			{

				// Here we start at the last character of the previous line
				// and check to see if it's a 'space' type charcter, if it is
				// we will then reduce the total size of the headers thus far and
				// move the pointer where we're going to append this new line back
				//	one more character - Ultimately what we wish to achieve is that
				//	the new line will tacked on [sans leading spaces] to the end of
				//	the previous line.
				//
				// 'p' holds the location at the -end- of the current headers where
				//		we are going to append the newly read line


				p = glb.headerline +totalsize -1;
				while (( *p == '\n' )||( *p == '\r' ))
				{
					*p = '\0';
					p--;
					totalsize--;
				}


				p = glb.headerline +totalsize -1;

				// According to RFC's, we must eliminate any leading spaces on the new
				//	line as they were used to indicate that the line was a 'wrap around'

				while ((*linestart == '\t')||(*linestart == ' '))
				{
					linestart++;
					linesize--;
				}

			} 


			memcpy((glb.headerline +totalsize), linestart, (linesize));
			totalsize += linesize;
			*(glb.headerline +totalsize) = '\0';


		}	// If the glb.headerline already is allocated and we're appending to it.


		if (f->trueblank)
		{
			if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIME_read_headers:DEBUG: Trueblank line detected in header reading",FL);
			MDECODE_decode_ISO( glb.headerline, totalsize  );

			if ((glb.save_headers)&&(glb.headerline))
			{
				fprintf(glb.header_file,"%s",glb.headerline);
			}
			if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIME_read_headers:DEBUG: Final Headers------------------\n%s---------------", FL,glb.headerline);
			//result = 1;
			//result = 0;
			break;
		} // If the last line was in fact a true blank line


		// If there was a doubleCR at the end of the line,
		//	then we need to save the next set of data until there
		//	is a \n

		if (FFGET_doubleCR)
		{
			if (glb.doubleCR_save != 0)
			{
				MIMEH_save_doubleCR(f);
				glb.doubleCR = 1;
			}
			FFGET_doubleCR = 0;
			FFGET_SDL_MODE = 0;
		} // FFGET_doubleCR test

		firstline = 0;
	} // While reading more headers from the source file.


	// If FFGET ran out of data whilst processing the headers, then acknowledge this
	// by returning a -1.
	//
	// NOTE - This does not mean we do not have any data!
	//  it just means that our input ran out.

	if (!fget_result)
	{
		if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIME_read_headers:ERROR: FFGET module ran out of input while reading headers",FL);
		result = -1;
	}

	return result;
}



/*------------------------------------------------------------------------
Procedure:     MIMEH_display_info ID:1
Purpose:       DEBUGGING - Displays the values of the hinfo structure to
stderr
Input:
Output:
Errors:
------------------------------------------------------------------------*/
int MIMEH_display_info( struct MIMEH_header_info *hinfo )
{
	if (hinfo)
	{
		LOGGER_log("%s:%d:MIMEH_display_info:\
				Content Type = %d\n\
				Boundary = %s\n\
				Filename = %s\n\
				name = %s\n\
				Encoding = %d\n\
				Disposit = %d\n\
				"\
				,FL\
				,hinfo->content_type\
				,hinfo->boundary\
				,hinfo->filename\
				,hinfo->name\
				,hinfo->content_transfer_encoding\
				,hinfo->content_disposition);
		fflush(stdout);
	}
	return 0; 

}


/*-----------------------------------------------------------------\
 Function Name	: MIMEH_recompose_multivalue
 Returns Type	: int
 	----Parameter List
	1. struct MIMEH_header_info *hinfo, 
	2.  char *header_name_prefix, 
	3.  char *header_value, 
	4.  char *buffer, 
	5.  size_t buffer_size , 
 	------------------
 Exit Codes	: 
 Side Effects	: 
--------------------------------------------------------------------
 Comments:
 
--------------------------------------------------------------------
 Changes:
 
\------------------------------------------------------------------*/
int MIMEH_recompose_multivalue( struct MIMEH_header_info *hinfo, char *header_name_prefix, char *header_value, char *buffer, size_t buffer_size )
{
	int result = 0;


	//LOGGER_log("%s:%d:DEBUG: seeking for %s in %s and appending to '%s'", FL, header_name_prefix, header_value,buffer );


	if (strstr(header_value, header_name_prefix) != NULL)
	{
		char *q;
		char *buffer_start;

		buffer_start = buffer +strlen(buffer);
		buffer_size -= strlen(buffer);

		q = header_value;
		// If the string we're looking for exists, then continue...
		do {
			char *p;
			char *end_point;

			p = strstr(q, header_name_prefix);
			if (p == NULL) break;

			//LOGGER_log("%s:%d:DEBUG: p = %s", FL, p);

			q = strchr(p,'=');
			if (q == NULL) break;
			q++;

			//LOGGER_log("%s:%d:DEBUG: q = %s", FL, q);

			end_point = strchr(q, ';');
			if (end_point != NULL) *end_point = '\0';

			// Trim off quotes.
			if (*q == '"') 
			{ 
				int bl;

			//	LOGGER_log("%s:%d:DEBUG: Trimming '%s'", FL, q);
				q++;
				bl = strlen(q);
				if (*(q +bl -1) == '"') *(q +bl -1) = '\0';
				//LOGGER_log("%s:%d:DEBUG: Trim done, '%s'", FL, q);
			}

			//LOGGER_log("%s:%d:DEBUG: filename segment = '%s'", FL, q);
			snprintf(buffer_start,buffer_size,"%s",q);
			buffer_size -= strlen(q);

			if (end_point != NULL){ *end_point = ';'; q = end_point +1; }
			else q = NULL;
		} while ((q != NULL)&&(buffer_size > 0));

	}

	return result;
}


/*-----------------------------------------------------------------\
  Function Name	: MIMEH_parse_header_parameter
  Returns Type	: int
  ----Parameter List
  1. char *data, 
  2.  char *searchstr, 
  3.  char *output_value, 
  4.  int output_value_size , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_parse_header_parameter( char *data, char *searchstr, char *output_value, int output_value_size )
{
	int return_value = 0;
	char *p;
	char *hl;

	hl = strdup(data);
	PLD_strlower(hl);

	if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_header_paramter:DEBUG: Seeking '%s'", FL, searchstr);
	p = strstr (hl, searchstr);
	if (p)
	{
		char *string = NULL;

		if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_header_parameter:DEBUG: found %s in %s", FL, searchstr, p);

		string = p -hl +data +strlen(searchstr);

		// skip any spaces
		while (isspace( *string ))
		{
			string++;
		}

		if ( *string != '=' )
		{
			if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_header_parameter:DEBUG: In '%s' parsing, was expecting a '=' in the start of '%s'\n", FL, searchstr, string );
			return_value = 1;
		}
		else {

			// we are at the '=' in the header, so skip it
			string++;

			// skip any spaces... again
			while ( isspace( *string ) )
			{
				string++;
			}

			if (((*string == '\"')&&(*(string +strlen(string)-1) == '\"'))
					|| ((*string == '\'')&&(*(string +strlen(string)-1) == '\'')) )
			{
				int slen = strlen(string) -2;
				char *s = string;
				if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse-header_parameter:DEBUG: Stripping quotes",FL);
				while (slen > 0)
				{
					*s = *(s+1);
					s++;
					slen--;
				}
				*s = '\0';

			}
			snprintf( output_value, output_value_size, "%s", string );
			if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_header_parameter:DEBUG: Final value = '%s'",FL, output_value);
		}

	}
	else {
		return_value = 1;
	}

	if (hl != NULL) free(hl);

	if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_header_parameter:DEBUG: [return=%d] Done seeking for '%s'",FL, return_value, searchstr);

	return return_value;

}











/*-----------------------------------------------------------------\
  Function Name	: MIMEH_parse_contenttype
  Returns Type	: int
  ----Parameter List
  1. char *header_name, 
  2.  char *header_value, 
  3.  struct MIMEH_header_info *hinfo , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_parse_contenttype( char *header_name, char *header_value, struct MIMEH_header_info *hinfo )
{

	int return_value;
	char *p, *q;
	char *hv = strdup( header_value );

	// CONTENT TYPE -------------------------------
	// CONTENT TYPE -------------------------------
	// CONTENT TYPE -------------------------------

	if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contenttype: Start",FL);

	p = strstr(header_name,"content-type");
	if (p != NULL)
	{
		if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contenttype: Content-type string found in header-name",FL);

		PLD_strlower( header_value );
		q = header_value;

		if (strstr(q,"multipart/appledouble")) hinfo->content_type = _CTYPE_MULTIPART_APPLEDOUBLE;
		else if (strstr(q,"multipart/signed")) hinfo->content_type = _CTYPE_MULTIPART_SIGNED;
		else if (strstr(q,"multipart/related")) hinfo->content_type = _CTYPE_MULTIPART_RELATED;
		else if (strstr(q,"multipart/mixed")) hinfo->content_type = _CTYPE_MULTIPART_MIXED;
		else if (strstr(q,"multipart/alternative")) hinfo->content_type = _CTYPE_MULTIPART_ALTERNATIVE;
		else if (strstr(q,"multipart/report")) hinfo->content_type = _CTYPE_MULTIPART_REPORT;
		else if (strstr(q,"multipart/")) hinfo->content_type = _CTYPE_MULTIPART;
		else if (strstr(q,"text/plain")) hinfo->content_type = _CTYPE_TEXT_PLAIN;
		else if (strstr(q,"text/html")) hinfo->content_type = _CTYPE_TEXT_HTML;
		else if (strstr(q,"text/")) hinfo->content_type = _CTYPE_TEXT;
		else if (strstr(q,"image/gif")) hinfo->content_type = _CTYPE_IMAGE_GIF;
		else if (strstr(q,"image/jpeg")) hinfo->content_type = _CTYPE_IMAGE_JPEG;
		else if (strstr(q,"image/")) hinfo->content_type = _CTYPE_IMAGE;
		else if (strstr(q,"audio/")) hinfo->content_type = _CTYPE_AUDIO;
		else if (strstr(q,"message/rfc822")) hinfo->content_type = _CTYPE_RFC822;
		else if (strstr(q,"/octet-stream")) hinfo->content_type = _CTYPE_OCTECT;
		else if (strstr(q,"/ms-tnef")) hinfo->content_type = _CTYPE_TNEF;
		else if (strstr(q,"application/applefile")) 
		{
			hinfo->content_type = _CTYPE_APPLICATION_APPLEFILE;
			if ( hinfo->filename[0] == '\0' ) 
			{
				if (strlen(glb.appledouble_filename)>0)
				{
					snprintf(hinfo->filename, sizeof(hinfo->filename), "%s.applemeta", glb.appledouble_filename );
				} else {
					snprintf(hinfo->filename, sizeof(hinfo->filename), "applefile");
				}
			}
		}
		else hinfo->content_type = _CTYPE_UNKNOWN;



		// Copy the string to our content-type string storage field
		p = header_value;
		if (p != NULL)
		{
			char *c = p;

			// Step 1 - jump over any whitespace
			while ( *c == ' ' || *c == '\t') c++;

			// Step 2 - Copy the string
			PLD_strncpy( hinfo->content_type_string, c, _MIMEH_CONTENT_TYPE_MAX);

			// Step 3 - clean up the string
			c = hinfo->content_type_string;
			while (*c && *c != ' ' && *c != '\t' && *c != '\n' && *c != '\r' && *c != ';') c++;

			// Step 4 - Terminate the string
			*c = '\0';
		}

		// If we have an additional parameter at the end of our content-type, then we 
		//	should search for a name="foobar" sequence.
		p = strchr( hv, ';' );
		if (p != NULL)
		{
			struct PLD_strtok tx;
			char *param;

			p++;
			param = PLD_strtok( &tx, p, ";\n\r" );
			while ( param != NULL )
			{
				if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contenttype:DEBUG: Parsing '%s'",FL,param);

				// Seek out possible 'filename' parameters 
				return_value = MIMEH_parse_header_parameter( param, "name", hinfo->name, sizeof(hinfo->name));
				if ( return_value == 0 )
				{
					if ( hinfo->filename[0] == '\0' ) {
						snprintf( hinfo->filename, sizeof(hinfo->filename), "%s", hinfo->name );
					}
				}

				// See out boundary specifications
				return_value = MIMEH_parse_header_parameter( param, "boundary", hinfo->boundary, sizeof(hinfo->boundary));
				if ( return_value == 0 ) {
					hinfo->boundary_located = 1;
					if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contenttype:DEBUG: Setting hinfo->boundary_located to %d",FL, hinfo->boundary_located );
				}

				param = PLD_strtok( &tx, NULL, ";\n\r" );
			} // While
		}
	}

	if (hv != NULL) free(hv);

	return 0;

}










/*-----------------------------------------------------------------\
  Function Name	: MIMEH_parse_contentlocation
  Returns Type	: int
  ----Parameter List
  1. char *header_name, 
  2.  char *header_value, 
  3.  struct MIMEH_header_info *hinfo , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_parse_contentlocation( char *header_name, char *header_value, struct MIMEH_header_info *hinfo )
{
	char *p, *q;

	// CONTENT LOCATION -------------------------------
	// CONTENT LOCATION -------------------------------
	// CONTENT LOCATION -------------------------------

	PLD_strlower( header_name );
	p = strstr(header_name,"content-location");
	if (p)
	{
		if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIME_parse_contentlocation:DEBUG: Content Location line found - '%s'\n", FL, header_value);


		p = q = header_value;
		while (q)
		{
			q = strpbrk(p, "\\/");
			if (q != NULL) p = q+1;
		}

		if (p)
		{
			if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIME_parse_contentlocation:DEBUG: filename = %s\n", FL, p);
			snprintf(hinfo->name, sizeof(hinfo->name),"%s",p);
			snprintf(hinfo->filename, sizeof(hinfo->name),"%s",p);

		}
	}

	return 0;

}














/*-----------------------------------------------------------------\
  Function Name	: MIMEH_parse_contenttransferencoding
  Returns Type	: int
  ----Parameter List
  1. char *header_name, 
  2.  char *header_value, 
  3.  struct MIMEH_header_info *hinfo , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_parse_contenttransferencoding( char *header_name, char *header_value, struct MIMEH_header_info *hinfo )
{
	char *p, *q;
	char c = '\n';

	// CONTENT TRANSFER ENCODING ---------------------
	// CONTENT TRANSFER ENCODING ---------------------
	// CONTENT TRANSFER ENCODING ---------------------


	p = strstr(header_name,"content-transfer-encoding");
	if (p)
	{
		q = strpbrk(header_value,"\n\r;");
		if (q != NULL)
		{
			c = *q;
			*q = '\0';
		}

		p = header_value;

		PLD_strlower( p );

		if (strstr(p,"base64"))
		{
			hinfo->content_transfer_encoding = _CTRANS_ENCODING_B64;
			if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contenttransferencoding: Encoding set to BASE64", FL);
		}
		else if (strstr(p,"7bit"))
		{
			hinfo->content_transfer_encoding = _CTRANS_ENCODING_7BIT;
			if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contenttransferencoding: Encoding set to 7-BIT ", FL);
		}
		else if (strstr(p,"8bit"))
		{
			hinfo->content_transfer_encoding = _CTRANS_ENCODING_8BIT;
			if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contenttransferencoding: Encoding set to 8-BIT", FL);
		}
		else if (strstr(p,"quoted-printable"))
		{
			hinfo->content_transfer_encoding = _CTRANS_ENCODING_QP;
			if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contenttransferencoding: Encoding set to Quoted-Printable", FL);
		}
		else if (strstr(p,"binary"))
		{
			hinfo->content_transfer_encoding = _CTRANS_ENCODING_BINARY;
			if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contenttransferencoding: Encoding set to Binary", FL);
		}
		else if (strstr(p,"uuencode"))
		{
			hinfo->content_transfer_encoding = _CTRANS_ENCODING_UUENCODE;
			if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contenttransferencoding: Encoding set to UUENCODE", FL);
		}
		else hinfo->content_transfer_encoding = _CTRANS_ENCODING_RAW;


		// Copy the string to our content-transfer string storage field
		p = header_value;
		if (p != NULL)
		{
			char *c = p;

			// Step 1 - jump over any whitespace
			while ( *c == ' ' || *c == '\t') c++;

			// Step 2 - Copy the string
			PLD_strncpy( hinfo->content_transfer_encoding_string, c, _MIMEH_CONTENT_TRANSFER_ENCODING_MAX);

			// Step 3 - clean up the string
			c = hinfo->content_transfer_encoding_string;
			while (*c && *c != ' ' && *c != '\t' && *c != '\n' && *c != '\r' && *c != ';') c++;

			// Step 4 - Terminate the string
			*c = '\0';
		}
		
		// Set the character which we changed to a \0 back to its original form so that
		//		we don't cause problems from tainted data for any further parsing calls
		//		which use the data.
		if (q != NULL) *q = c;
	}

	return 0;

}

/*-----------------------------------------------------------------\
  Function Name	: MIMEH_parse_contentdisposition
  Returns Type	: int
  ----Parameter List
  1. char *header_name, 
  2.  char *header_value, 
  3.  struct MIMEH_header_info *hinfo , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_parse_contentdisposition( char *header_name, char *header_value, struct MIMEH_header_info *hinfo )
{
	char  *p;
	char *hv = strdup(header_value);

	// CONTENT DISPOSITION ------------------------------
	// CONTENT DISPOSITION ------------------------------
	// CONTENT DISPOSITION ------------------------------

	//LOGGER_log("%s:%d:DEBUG: Headers='%s'",FL,header_value);
	p = strstr(header_name,"content-disposition");
	if (p != NULL)
	{
		p = header_value;
		PLD_strlower( header_value );

		if (strstr(p,"inline")) 
		{
			hinfo->content_disposition = _CDISPOSITION_INLINE;
		} 
		else if (strstr(p,"form-data"))
		{
			hinfo->content_disposition = _CDISPOSITION_FORMDATA;
		}
		else if (strstr(p,"attachment")) 
		{
			hinfo->content_disposition = _CDISPOSITION_ATTACHMENT;
		}
		else
		{
			hinfo->content_disposition = _CDISPOSITION_UNKNOWN;
		}
		
		// Copy the string to our content-transfer string storage field
		if (p != NULL)
		{
			char *q = p;

			// Step 1 - jump over any whitespace
			while ( *q == ' ' || *q == '\t') q++;

			// Step 2 - Copy the string
			PLD_strncpy( hinfo->content_disposition_string, q, _MIMEH_CONTENT_DISPOSITION_MAX);

			// Step 3 - clean up the string
			q = hinfo->content_disposition_string;
			while (*q && *q != ' ' && *q != '\t' && *q != '\n' && *q != '\r' && *q != ';') q++;

			// Step 4 - Terminate the string
			*q = '\0';
		}

		//LOGGER_log("%s:%d:Disposition string = '%s'",FL, hv);

		p = strchr( hv, ';' );
		if (p != NULL)
		{
			struct PLD_strtok tx;
			char *param;

			hinfo->name[0]='\0';

			p++;
			param = PLD_strtok( &tx, p, ";\n\r" );
			while ( param != NULL )
			{
				int parse_result;

				if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contentdisposition:DEBUG: Parsing '%s'",FL,param);

				// Seek out possible 'filename' parameters 

				parse_result = MIMEH_parse_header_parameter( param, "filename", hinfo->name, sizeof(hinfo->name));
				if (parse_result != 0) parse_result = MIMEH_recompose_multivalue( hinfo, "filename", param, hinfo->name, sizeof(hinfo->name));
				//LOGGER_log("%s:%d:DEBUG: hinfo->name = %s",FL,hinfo->name);
				/*
				if (parse_result == 0)
				{
				}
				*/

				param = PLD_strtok( &tx, NULL, ";\n\r" );
			} // While

			if ( hinfo->filename[0] == '\0' ) 
			{
				//LOGGER_log("%s:%d:DEBUG: Transferring hinfo->name to hinfo->filename",FL);
				snprintf( hinfo->filename, sizeof(hinfo->filename), "%s", hinfo->name );
			}

			// Handle situations where we'll need the filename for the future.
			if ( hinfo->content_type == _CTYPE_MULTIPART_APPLEDOUBLE )
			{
				snprintf( glb.appledouble_filename, sizeof(glb.appledouble_filename), "%s", hinfo->filename );	
				if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_contentdisposition:DEBUG: Setting appledouble filename to: '%s'",FL,glb.appledouble_filename);
			}

		} // If the header-value contained ;'s ( indicating parameters )

	} // If the header-name actually contained 'content-disposition'

	if (hv != NULL) free(hv);

	return 0;
}




/*-----------------------------------------------------------------\
 Function Name	: MIMEH_parse_subject
 Returns Type	: int
 	----Parameter List
	1. char *header_name,  contains the full headers
	2.  char *header_value, 
	3.  struct MIMEH_header_info *hinfo , 
 	------------------
 Exit Codes	: 
 Side Effects	: 
--------------------------------------------------------------------
 Comments:
 
--------------------------------------------------------------------
 Changes:
 
\------------------------------------------------------------------*/
int MIMEH_parse_subject( char *header_name, char *header_value, struct MIMEH_header_info *hinfo )
{
	char *subject_location;

	subject_location = strstr( header_name, "subject" );
	if (subject_location != NULL)
	{
		// We've found subject in the header name...
		snprintf( hinfo->subject, _MIMEH_SUBJECTLEN_MAX, "%s", header_value );
	}

	return 0;
}

/*-----------------------------------------------------------------\
  Function Name	: MIMEH_process_headers
  Returns Type	: int
  ----Parameter List
  1. struct MIMEH_header_info *hinfo, 
  2.  char *headers , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_headers_process( struct MIMEH_header_info *hinfo, char *headers )
{
	char *safeh, *h, *safehl;
	char *current_header_position;
	int headerlength;

	if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_headers:DEBUG: Start [hinfo=%p]\n",FL, hinfo);

	safeh = h = headers;

	// Duplicate the headers for processing - this way we don't 'taint' the
	// original	headers during our searching / altering.

	headerlength = strlen(h);
	safehl = malloc(sizeof(char) *(headerlength+1));
	PLD_strncpy(safehl, h, headerlength+1);

	if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIME_parse_headers:DEBUG: Header length = %d\n", FL,headerlength);

	current_header_position = h;

	// Searching through the headers, we seek out header 'name:value;value;value' sets,
	//		Each set is then cleaned up, seperated and parsed.

	while ((current_header_position != NULL)&&( current_header_position <= (h +headerlength) ))
	{
		char *header_name, *header_value;
		char *header_name_end_position;
		char *header_value_end_position;

		// Tokenise for the header 'name', ie, content-type, subject etc
		header_name = current_header_position;
		header_name_end_position = strchr( header_name, ':' );

		// Seek forward from the start of our header, looking for the first occurance
		//		of the line end (implying the end of the current header name:value,
		//		we can do this because we know that when the headers were read in, we
		//		have already unfolded them, such that there should only be one header:value
		//		pairing per 'line'.

		current_header_position = strpbrk( current_header_position, "\n\r");
		if ( current_header_position == NULL )
		{
			// Theoretically, this should not happen, as headers are always
			//		terminated with a \n\r\n\r finishing byte sequence, thus
			//		if this _does_ happen, then we will simply jump out of the 
			//		current iteration and let the loop try find another pairing
			//
			// There probably should be a logging entry here to indicate that
			//		"something strange happened"

			continue;
		} else {
			
			// Shuffle our CHP (current-header-position) pointer along the header
			//		data until it is no longer pointing to a \r or \n, this is so
			//		that when the next iteration of this loop comes around, it'll
			//		immediately be in the right place for starting the next parse

			while (( *current_header_position == '\n') ||( *current_header_position == '\r' )) current_header_position++;
		}

		if (( header_name_end_position == NULL )||( header_name_end_position > current_header_position))
		{ 
			// Some headers can contain various levels of non name/value pairings,
			//		while their presence could be debatable in terms of RFC validity
			//		we will 'ignore' them rather than throwing up our arms.  This 
			//		ensures that we are not made to break over spurilous data.

			if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_headers:DEBUG: This line contains no header:value pair", FL);
			continue;

		} else {

			// Get the header-value string and prepare to
			//		parse the data through our various parsing 
			//		functions.

			header_value = header_name_end_position +1;
			header_value_end_position = strpbrk( header_value, "\n\r" );
			if ( header_value_end_position != NULL )
			{
				*header_name_end_position = '\0';
				*header_value_end_position = '\0';
				if (MIMEH_DNORMAL)
				{
					LOGGER_log("%s:%d:MIMEH_parse_headers:DEBUG: Header Name ='%s'", FL, header_name );
					LOGGER_log("%s:%d:MIMEH_parse_headers:DEBUG: Header Value='%s'", FL, header_value );
				}

				// To make parsing simpler, convert our
				//		header name to lowercase, that way
				//		we also reduce the CPU requirements for 
				//		searching because pre-lowering the header-name
				//		occurs once, but string testing against it
				//		occurs multiple times ( at least once per parsing

				PLD_strlower( header_name );
				MIMEH_parse_subject( header_name, header_value, hinfo );
				MIMEH_parse_contenttype( header_name, header_value, hinfo );
				MIMEH_parse_contenttransferencoding( header_name, header_value, hinfo );
				MIMEH_parse_contentdisposition( header_name, header_value, hinfo );
				if (hinfo->filename[0] == '\0')
				{
					MIMEH_parse_contentlocation( header_name, header_value, hinfo );
				}

			} else {
				if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_headerss:DEBUG: Header value end position is NULL",FL);
			}
		}



	} // while

	// Final analysis on our headers:
	if ( hinfo->content_type == _CTYPE_MULTIPART_APPLEDOUBLE )
	{
		char tmp[128];
		snprintf( tmp, sizeof(tmp), "mac-%s", hinfo->filename );
		snprintf( hinfo->filename, sizeof(hinfo->filename), "%s", tmp );
		snprintf( hinfo->name, sizeof(hinfo->name), "%s", tmp );
	}
	
	// PLD:20031205
	// Act like Outlook *God forbid!* and if there's a octect-stream 
	//	content-type, but the encoding is still null/empty, then 
	//	change the content-encoding to be RAW

	if ( hinfo->content_type == _CTYPE_OCTECT )
	{
		if ((hinfo->content_transfer_encoding == _CTRANS_ENCODING_UNSPECIFIED)
		|| (hinfo->content_transfer_encoding == _CTRANS_ENCODING_UNKNOWN)
		|| (strlen(hinfo->content_transfer_encoding_string) < 1)
		)	
		{
			//LOGGER_log("%s:%d:DEBUG: Encoding pair was octet but no encoding, filename=%s\n",FL,hinfo->filename);
			hinfo->content_transfer_encoding = _CTRANS_ENCODING_RAW;
		}
	}


	if (safehl)
	{
		free(safehl);
	}
	else LOGGER_log("%s:%d:MIME_parse_headers:WARNING: Unable to free HEADERS allocated memory\n", FL);

	if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_headers:DEBUG: END [ hinfo=%p]\n", FL, hinfo);

	return 0;
}


/*-----------------------------------------------------------------\
  Function Name	: MIMEH_get_headers
  Returns Type	: int
  ----Parameter List
  1. struct MIMEH_header_info *hinfo, 
  2.  FFGET_FILE *f , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_headers_get( struct MIMEH_header_info *hinfo, FFGET_FILE *f )
{
	int result = 0;

	// Setup some basic defaults 
	hinfo->filename[0] = '\0';
	hinfo->name[0] = '\0';
	hinfo->content_type = _CTYPE_UNKNOWN;

	// 20040116-1234:PLD - added to appease valgrind
	hinfo->content_disposition = 0;
	hinfo->content_transfer_encoding = 0;
	hinfo->boundary_located = 0;

	snprintf( hinfo->content_type_string, _MIMEH_CONTENT_TYPE_MAX , "text/plain" ); 


	// Read from the file, the headers we need
	FFGET_set_watch_SDL(1);
	result = MIMEH_read_headers(f);
	FFGET_set_watch_SDL(0);


	// If we ran out of input whilst looking at headers, then, we basically
	// flag this, free up the headers, and return.
	if (result == -1)
	{
		if (glb.headerline) free(glb.headerline);
		return result;
	}

	// If we came back with an OKAY result, but there's nothing in the
	//	headers, then flag off an error
	if (glb.headerline == NULL)
	{
		if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIME_parse_headers:DEBUG: null headerline\n", FL);
		return 1;
	}

	return result;
}

/*-----------------------------------------------------------------\
  Function Name	: MIMEH_headers_cleanup
  Returns Type	: int
  ----Parameter List
  1. void , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_headers_cleanup( void )
{
	if (glb.headerline != NULL)
	{
		free(glb.headerline);
		glb.headerline = NULL;
	}

	if (glb.headerline_original != NULL)
	{ 
		free(glb.headerline_original);
		glb.headerline_original = NULL;
	} 

	return 0;
}



/*-----------------------------------------------------------------\
  Function Name	: MIMEH_parse_headers
  Returns Type	: int
  ----Parameter List
  1. FFGET_FILE *f, 
  2.  struct MIMEH_header_info *hinfo , 
  ------------------
  Exit Codes	: 
  Side Effects	: 
  --------------------------------------------------------------------
Comments:

--------------------------------------------------------------------
Changes:

\------------------------------------------------------------------*/
int MIMEH_parse_headers( FFGET_FILE *f, struct MIMEH_header_info *hinfo )
{
	int result = 0;
	if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_headers:DEBUG: Start [F=%p, hinfo=%p]\n", FL, f, hinfo);

	if ( result == 0 ) result = MIMEH_headers_get( hinfo, f );
	if ( result == 0 ) result = MIMEH_headers_process( hinfo, glb.headerline );
	if ( result == 0 ) result = MIMEH_headers_cleanup(); 

	if (MIMEH_DNORMAL) LOGGER_log("%s:%d:MIMEH_parse_headers:DEBUG: END [F=%p, hinfo=%p]\n", FL, f, hinfo);

	return result;
}


//----------------------END

