/*-----------------------------------------------------------------\
 Function Name	: OLEUNWRAP_save_stream
 Returns Type	: int
 	----Parameter List
	1. char *fname,
	2.  char *stream,
	3.  size_t bytes ,
 	------------------
 Exit Codes	:
 Side Effects	:
--------------------------------------------------------------------
 Comments:

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

\------------------------------------------------------------------*/
int OLEUNWRAP_save_stream( struct OLEUNWRAP_object *oleuw, char *fname, char *decode_path, char *stream, size_t bytes )
{
	char *full_name;
	FILE *f;
	int result = 0;

	DUW LOGGER_log("%s:%d:OLEUNWRAP_save_stream:DEBUG: fname=%s, decodepath=%s, size=%ld"
			,FL
			,fname
			,decode_path
			,bytes
			);

	full_name = PLD_dprintf("%s/%s", decode_path, fname );
	if (full_name == NULL)
	{
		LOGGER_log(_("%s:%d:OLEUNWRAP_save_stream:ERROR: Unable to create filename string from '%s' and '%s'"),FL,fname,decode_path);
		return -1;
	}

	wcfopen(f, full_name, "wb");
	if (f != NULL)
	{
		size_t write_count;

		write_count = fwrite( stream, 1, bytes, f );
		if (write_count != bytes)
		{
			LOGGER_log(_("%s:%d:OLEUNWRAP_save_stream:WARNING: Only wrote %d of %d bytes to file %s\n"),FL, write_count, bytes, full_name );
		}

		fclose(f);


	} else {
		LOGGER_log(_("%s:%d:OLEUNWRAP_save_stream:ERROR: Unable to open %s for writing (%s)\n"),FL,full_name, strerror(errno));
		result = -1;
	}

	if (full_name) FREE(full_name);

	DUW LOGGER_log("%s:%d:OLEUNWRAP_save_stream:DEBUG: Done saving '%s'",FL, fname);

	return result;
}
/*-----------------------------------------------------------------\
 Function Name	: RIPMIME_report_filename_decoded
 Returns Type	: int
 	----Parameter List
	1. char *filename, 
	2.  char *contenttype, 
 	------------------
 Exit Codes	: 
 Side Effects	: 
--------------------------------------------------------------------
 Comments:
 
--------------------------------------------------------------------
 Changes:
 
\------------------------------------------------------------------*/
int RIPMIME_report_filename_decoded (char *filename, char *contenttype)
{
	char *p;

	p = strrchr(filename,'/');
	if (!p) p = filename; else p++;

	if (contenttype != NULL)
	{
		LOGGER_log ("Decoding content-type=%s filename=%s", contenttype, p);
	}
	else
	{
		LOGGER_log ("Decoding filename=%s", p);
	}

	return 0;
}
Exemple #3
0
int qp_encode_from_file( char *fname )
{
	size_t bc;
	struct stat st;
	int stat_result;
	char *in_buffer;
	char *out_buffer;
	size_t in_size, out_size;
	FILE *f;

	stat_result = stat( fname, &st );
	if (stat_result != 0){
		QPD fprintf(stderr, "Cannot locate file '%s' for loading and QP encoding (%s)\n", fname, strerror(errno));
		return -1;
	}


	in_size = st.st_size;
	out_size = in_size *3;
	in_buffer = malloc( sizeof(char) *in_size +1);
	if (in_buffer == NULL) {
		QPD fprintf(stdout,"Error allocating %d bytes for input buffer\n", in_size);
		return -1;
	}

	out_buffer = malloc( sizeof(char) *out_size *3 +1);
	if (in_buffer == NULL) {
		QPD fprintf(stdout,"Error allocating %d bytes for output buffer\n", out_size);
		return -1;
	}


	f = fopen( fname, "r" );
	bc = fread( in_buffer, 1, in_size, f );
	if (bc != in_size) LOGGER_log("%s:%d:qp_encode_from_file:ERROR: Read %d bytes but requested %d", FL, bc, in_size);
	fclose(f);

	/** zero terminate the buffer -- uhuh, if you forget that you'll wonder why
	  ** we segfault ;)  **/
	*(in_buffer +in_size) = '\0';

	QPD fprintf(stdout,"file %s is loaded, size = %d\n", fname, in_size);

	qp_encode( out_buffer, out_size, in_buffer, in_size );

	fprintf( stdout, "%s", out_buffer );

	free(in_buffer);
	free(out_buffer);

	return 0;
}
/*-----------------------------------------------------------------\
 Function Name	: OLEUNWRAP_decodestream
 Returns Type	: int
 	----Parameter List
	1. char *element_string,
	2.  char *stream ,
 	------------------
 Exit Codes	:
 Side Effects	:
--------------------------------------------------------------------
 Comments:

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

\------------------------------------------------------------------*/
int OLEUNWRAP_decodestream( struct OLEUNWRAP_object *oleuw, char *element_string, char *stream, size_t stream_size, char *decode_path )
{
	int result = OLEUW_OK;

	if (strstr(element_string, OLEUW_ELEMENT_10NATIVE_STRING) != NULL)
	{
		OLEUNWRAP_decode_attachment( oleuw, stream, stream_size, decode_path );

	} else {
		if (oleuw->debug) LOGGER_log(_("Unable to decode stream with element string '%s'\n"), element_string);
		result = OLEUW_STREAM_NOT_DECODED;
	}

	return result;
}
Exemple #5
0
/*-----------------------------------------------------------------\
  Function Name	: FFGET_seek
  Returns Type	: int
  ----Parameter List
  1. FFGET_FILE *f, 
  2.  size_t offset , 
  ------------------
  Exit Codes	: 
  -1 = error, check logs for reason of failure.

  Side Effects	: 
  --------------------------------------------------------------------
Comments:
Seeks to 'offset' bytes from the first byte of the file.
Reloads the buffer block.

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

\------------------------------------------------------------------*/
int FFGET_seek( FFGET_FILE *f, long offset, int whence )
{
	int result = 0;

	/** Move to the new block location **/
	result = fseek(f->f, offset, whence);
	if (result == -1) {
		LOGGER_log("%s:%d:FFGET_seek:ERROR: While attempting to seek to offset %ld from %d - [%s]", FL, offset, whence, strerror(errno));
		return -1;
	}

	/** Read a whole new block **/
	result = FFGET_getnewblock(f);

	return result;
}
/*-----------------------------------------------------------------\
 Function Name	: OLEUNWRAP_decode_attachment
 Returns Type	: int
 	----Parameter List
	1. char *stream ,
 	------------------
 Exit Codes	:
 Side Effects	:
--------------------------------------------------------------------
 Comments:

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

\------------------------------------------------------------------*/
int OLEUNWRAP_decode_attachment( struct OLEUNWRAP_object *oleuw, char *stream, size_t stream_size, char *decode_path )
{
	struct OLE10_header oh;
	char *sp = stream;
	char *data_start_point = stream;
	int result = OLEUW_OK;

	/* Get the data size*/
	oh.attach_size_1 = (size_t)get_4byte_value( (unsigned char *) sp );
	sp += 4;

	DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: attachsize = %d, stream length = %d\n", FL, oh.attach_size_1, stream_size );

	oh.attach_start_offset = (stream_size -oh.attach_size_1);
	data_start_point = stream +oh.attach_start_offset;

	/*if (oh.attach_start_offset == 4)*/
	if (oh.attach_start_offset < 4)
	{
	  /* If we only had the stream byte-lenght in our header*/
	  /*		then we know we don't have a complex header.*/
		oh.attach_name = PLD_dprintf("unknown-%ld",oh.attach_size_1);
		oh.attach_size = oh.attach_size_1;
	} else {

		DUW LOGGER_log("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Decoding file information header",FL);
		/* Unknown memory segment*/
		memcpy( oh.data, sp, 2 );
		sp += 2;

		/* Full attachment string*/
		oh.attach_name = strdup( sp );
		sp = sp + strlen(oh.attach_name) +1;

		/* Attachment full path*/
		oh.fname_1 = strdup( sp );
		sp += strlen(oh.fname_1) +1;

		/* Unknown memory segment*/
		memcpy( oh.data2, sp, 8 );
		sp = sp +8;

		/* Attachment full path*/
		oh.fname_2 = strdup( sp );
		sp += strlen(oh.fname_2) +1;

		oh.attach_size = (size_t)get_4byte_value( (unsigned char*) sp );
		sp += 4;

		if (oh.attach_size > stream_size) oh.attach_size = stream_size;

		data_start_point = sp;
	}

	DUW LOGGER_log(_("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Attachment %s:%s:%s size = %d\n"),FL, oh.attach_name, oh.fname_1, oh.fname_2, oh.attach_size );


	/** 20050119:2053:PLD - Added to sanitize 8-bit filenames **/
	/** Sanitize the output filename **/
	OLEUNWRAP_sanitize_filename(oh.attach_name);
	OLEUNWRAP_sanitize_filename(oh.fname_1);
	OLEUNWRAP_sanitize_filename(oh.fname_2);

	result = OLEUNWRAP_save_stream( oleuw, oh.attach_name, decode_path, data_start_point, oh.attach_size );
	if (result == OLEUW_OK)
	{
		if (oleuw->debug > 0) LOGGER_log(_("%s:%d:OLEUNWRAP_decode_attachment:DEBUG: Calling reporter for the filename"),FL);
		if ((oleuw->verbose > 0)&&(oleuw->filename_report_fn != NULL))
		{
			oleuw->filename_report_fn(oh.attach_name);
		}
		/* Do call back to reporting function*/
	}

	/* Clean up our previously allocated data*/
	if (oh.fname_1 != NULL) FREE(oh.fname_1);
	if (oh.attach_name != NULL) FREE(oh.attach_name);
	if (oh.fname_2 != NULL) FREE(oh.fname_2);

	return OLEUW_OK;
}
Exemple #7
0
/*------------------------------------------------------------------------
Procedure:     FFGET_fgets ID:1
Purpose:       Gets a single line from the input buffer. The line can be
either \r \n \r\n terminated based on the status flags set/unset
by previous reads.   This function is the key to making
tools like ripMIME be able to see double-vision, that is, to see
emails like Outlook does, and also like RFC.
Input:         line: Buffer to write to
max_size: Maximum number of bytes to write to line.
f: FFGET record to use to read.
Output:        Pointer to line.
Errors:
------------------------------------------------------------------------*/
char *FFGET_fgets( char *linein, int maxsize, FFGET_FILE *f )
{
	char *line = linein;
	char *crlfpos = NULL;
	int charstoCRLF = 0;
	int chardiff = 0;
	int result = 0;
	int max_size = maxsize;
	int endpoint_tainted = 0;
	int extra_char_kept=0;
	int c, nextchar;

	f->trueblank = 0;
	f->linebreak = FFGET_LINEBREAK_NONE;
	f->lastbreak[0] = '\0';

	if (f->FFEOF != 0)
	{
		return NULL;
	}

	if ((FFGET_SDL_WATCH > 0)||(FFGET_SDL_MODE != 0))
	{
		DELIMITERS = SDL_MODE_DELIMITS;
	}
	else DELIMITERS = NORM_MODE_DELIMITS;


	//	fprintf(stderr,"FFGET_called, SDLMODE = %d, Offset = %d, maxsize = %d, DATA left = %d, first char is '%02X'\n", FFGET_SDL_MODE, (f->startpoint -f->buffer), max_size, (f->endpoint -f->startpoint)+1, (int)(*f->startpoint));

	max_size = maxsize = maxsize -2;

	//	memset(line, 0, max_size+1);

	// If we dont have enough data in the buffer to fill up the fgets request
	// we'll have to do a two step fill

	//fprintf(stderr,"DATA Reminianing : %d\n", (int)(f->endpoint -f->startpoint)+1);

	if ((f->startpoint > f->endpoint))
	{
		result = FFGET_getnewblock(f);
		if (result == 0)
		{
			*linein = '\0';
			return NULL;
		}
	}



	// This loop does not go around too many times, once, maybe twice max.

	while ((max_size > 0)&&(f->FFEOF == 0))
	{

		crlfpos = strpbrk( f->startpoint, DELIMITERS);
		if (crlfpos)
		{
				extra_char_kept = 0;
				endpoint_tainted = 0;
				nextchar = -1;
			// if our next char is a CR or LF, then pick it up and
			// return it with the line.  NOTE - this is to deal with
			// CRLF pairings which are common on DOS files.  In fact,
			// this is a case of where UNIX is actually -wrong-.  It
			// should have also used CRLF pairing to mark line ends, but
			// someone obviously (and understandably, to save space)
			// thought they'd leave make LF imply a CR as well.
			//   Well done... another bugger up in life.


			// The logic of this nested IF statement is as follows...
			//	If we do have another char available...
			//		and if the pairing is not \n\n (which should be treated as two lines
			//			and if the next char is a \n or a \r,
			//				THEN we should increment the end of line pointer so that we
			//				include the additional \n or \r into the line we're going to
			//				return

			// If we are NOT in the Single-delimeter mode (SDL_MODE), and the next
			// char is available, then commence the delimeter testing routines

			if ((0==f->FILEEND)&&(0==f->FFEOF)&&( ((crlfpos +1) >  f->endpoint)))
			{

				// We have an EOL character, get 1 more from the stream to test the next character


				nextchar = c = fgetc(f->f);
				if (c==EOF)
				{
					//					fprintf(stderr,"EOF hit due to fgetc()\n");
					f->FILEEND = 1;
				}
				else
				{
					if (c == '\0') c = ' ';

					// Check for character value vadality

					if ((c > 0) && (c <= 255))
					{
						if (FFGET_DNORMAL) LOGGER_log("%s:%d:FFGET_fgets:DEBUG: Tainting endpoint +1 (%p -> %p,  hard buffer end = %p, file read bytes = %ld)", FL, f->endpoint, f->endpoint+1, f->buffer_end, f->bytes);
						f->endpoint++;
						*(f->endpoint) = c;
						*(f->endpoint+1) = '\0';
						endpoint_tainted = 1;
					}

				}
			} // If (crlfpos +1) is /not/ within our buffer bounds


			// If the next char from our CRLF pickup is within the bounds of
			// our endpoint, then proceed to test the CRLF combo

			if ( ((crlfpos +1) <= f->endpoint))
			{

				//				fprintf(stderr,"Found '%02X' [next is '%02X']\n",*crlfpos, *(crlfpos+1));

				if ( *crlfpos == '\n' )
				{
					f->linebreak = FFGET_LINEBREAK_LF;
					snprintf(f->lastbreak,sizeof(f->lastbreak),"\n");

					if ( *(crlfpos +1) == '\r' )
					{
						f->linebreak |= FFGET_LINEBREAK_CR;
						snprintf(f->lastbreak,sizeof(f->lastbreak),"\n\r");
						crlfpos++;
						extra_char_kept = 1;
					}
				}


				// If our combo starts with a \r, then test it to see
				// if we have another \r after it, in which case, we
				// turn on SINGLE_DELIMETER_MODE.

				if ( (*crlfpos == '\r') )
				{
					f->linebreak = FFGET_LINEBREAK_CR;
					snprintf(f->lastbreak,sizeof(f->lastbreak),"\r");

					if ( *(crlfpos +1) == '\r' )
					{
						// A \r\r sequence has just been detected, set our doubleCR flag
						// 	so that MIME_headers can read it and react accordingly.
						// Look out for single \r's from here on, as they are now seen as
						// 	EOL markers in Outlook.

						f->linebreak = FFGET_LINEBREAK_CR;
						FFGET_doubleCR=1;
						FFGET_SDL_MODE=1;
						crlfpos++;
						extra_char_kept = 1;

					} else if ( *(crlfpos +1) == '\n' ) {
						// If we see a \n after our \r, then treat this as a single
						// 	line delimeter if we are NOT in Single Delimeter mode
						//

						snprintf(f->lastbreak,sizeof(f->lastbreak),"\r\n");
						f->linebreak |= FFGET_LINEBREAK_LF;
						if (!FFGET_SDL_MODE) {
						  	crlfpos++;
							extra_char_kept = 1;
					  	}// 20040208-1706:PLD
						//crlfpos++;// 20040208-1706:PLD	 // 20040306-0003:PLD - this line causes a CRCR test to fail; mailpack.virus.badtrans
					} else {
						// If we saw a \r, but then there was no other EOL type char (\r or \n)
						//	then switch to SDL mode (Single delimeter).

						FFGET_SDL_MODE=1;

					}

				} // If combo starts with a \r

			} // If crlfpos +1  is within the bounds of our buffer.

			// Determine how many characters/bytes there are from the startpoint,
			// to the CRLF position.


			charstoCRLF	= crlfpos -f->startpoint;

			// If the number of chars is -less- than that of the maximum line read
			// size which our calling program has specified, then we set the max_size
			// to be the number of chars.

			//DEBUG			fprintf(stderr, "MAX_size = %d, charstoCRLF = %d\n", max_size, charstoCRLF);

			if ((charstoCRLF >= 0)&&(charstoCRLF < max_size)) max_size = charstoCRLF;

			if ((extra_char_kept == 0) && (nextchar != -1)) ungetc(nextchar,f->f);

		} // If CRLF pos found.


		//		else crlfpos = (f->endpoint +1);




		// If the buffer amount remaining in our FFGET buffer is greater than
		// the maximum size available in our line buffer, then we
		//  only copy the max_size amount across

		if (( f->endpoint -f->startpoint) >= max_size)
		{
			if (max_size < 0) LOGGER_log("%s:%d:FFGET_fgets:ERROR: Max size < 0\n", FL);
			memcpy(line, f->startpoint, max_size +1);//+1
			f->startpoint += (max_size +1); //+1
			*(line +max_size +1) = '\0'; //+1
			max_size = 0;

		} else {

			// else, if the amount of data available is /LESS/ than what we can
			// accept in the line buffer then copy what remains out to the line
			// buffer and then tack on the results of a new read.

			chardiff = f->endpoint -f->startpoint;

			//			fprintf(stderr,"CHARDiff = %d, FFEOF = %d, FILEEND = %d\n",chardiff, f->FFEOF, f->FILEEND);

			if (chardiff >= 0)
			{
				memcpy(line, f->startpoint, chardiff +1);
				*(line +chardiff +1) = '\0';  // 12-11-2002: Added this line to terminate the input buffer incase it wasn't already flushed with \0's
				line += (chardiff +1);
				max_size -= (chardiff +1);
				f->startpoint = f->endpoint +1;
				if (max_size < 0) max_size = 0;
			}

			FFGET_getnewblock(f);
			endpoint_tainted=0;

		} // If there wasn't enough data to satisfy ends.

		if (endpoint_tainted) {
			FFGET_getnewblock(f);
			endpoint_tainted = 0;
		}

	} // While we've got space to fill, and we've got data to read

	line = linein;

	f->trueblank = 0;

	if ((f->lastchar == '\n')||(f->lastchar == '\r'))
	{
		if ((line[0] == '\n')||(line[0] == '\r'))
		{
			f->trueblank = 1;
		}
	}

	f->lastchar = line[strlen(line) -1];

	f->linecount++;

	//	LOGGER_log("%s:%d:LINE='%s'",FL,linein);

	return linein;
}
Exemple #8
0
/*------------------------------------------------------------------------
Procedure:     FFGET_getnewblock ID:1
Purpose:       Reads a new block of data from the input file
Input:         FFGET_FILE record
Output:        Returns number of bytes read
Errors:
------------------------------------------------------------------------*/
int FFGET_getnewblock( FFGET_FILE *f )
{
	int i;
	int bs = 0;
	char *p;

	// We read the maximum of FFGET_BUFFER_MAX -2, because later, when we
	// use fgets(), we may need to read in an /additional/ single byte
	// and if we dont allocate spare room, we may have a buffer overflow

	if (f->FILEEND > 0)
	{
		f->endpoint = f->buffer;
		f->startpoint = f->buffer +1;
		f->FFEOF = 1;
		return 0;

	} else {
		long block_pos;

		block_pos = ftell(f->f); /** Get our current read position so we can use it in FFGET_ftell if required **/

		bs = fread( f->buffer, 1, FFGET_BUFFER_MAX -FFGET_BUFFER_PADDING, f->f );

		if (bs < (FFGET_BUFFER_MAX -FFGET_BUFFER_PADDING))
		{
			if (feof(f->f))
			{
				f->FILEEND = 1;
			}
			else
			{
				LOGGER_log("%s:%d:FFGET_getnewblock:ERROR: File read failed with error:%s", FL, strerror(errno));
				return 0;
			}
		}

		if (bs > 0)
		{

			// If we read in some data, then adjust the buffer to deal with it
			//
			// First we set the start point back to the start of the buffer,
			// then we set the end point to be the start +datasize we read, -1
			// then we adjust the total bytes read (for the sake of record keeping
			// though it has no /real/ purpose)
			//

			f->buffer[bs] = '\0';	//20040208-1703:PLD:JS
			f->last_block_read_from = block_pos; // 200607150941:PLD
			f->startpoint = f->buffer;
			f->endpoint = f->startpoint +bs -1;
			f->bytes += bs;

			// Check the buffer for poisioning \0's
			//  As these routines are being used for 7-bit valid text data,
			// we have to filter out any nasty \0's.

			if (FFGET_ALLOW_NUL == 0)
			{
				p = f->startpoint;
				for (i = 0; i < bs; i++) {
					if (*p == '\0') *p = ' ';
					p++;
				}
				*p = '\0';
			}

			if (FFGET_DPEDANTIC) LOGGER_log("%s:%d:FFGET_getnewblock:DEBUG-PEDANTIC: Size: %ld bytes\n", FL, f->bytes);

		}

	}

	return bs;
}
Exemple #9
0
/*-----------------------------------------------------------------\
  Function Name	: *PLD_strreplace
  Returns Type	: char
  ----Parameter List
  1. char *source,		Original buffer, \0 terminated
  2.  char *searchfor, String sequence to search for
  3.  char *replacewith, String sequence to replace 'searchfor' with
  4.  int replacenumber , How many times to replace 'searchfor', 0 == unlimited
  ------------------
  Exit Codes	: Returns a pointer to the new buffer space.  The original
  buffer will still remain intact - ensure that the calling
  program FREE()'s the original buffer if it's no longer
  needed
  Side Effects	:
  --------------------------------------------------------------------
Comments:
Start out with static text matching - upgrade to regex later.

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

\------------------------------------------------------------------*/
char *PLD_strreplace_general( struct PLD_strreplace *replace_details )
{
    char *new_buffer = NULL;
    char *source_end;
    char *segment_start, *segment_end, *segment_p;
    char *new_p;
    char *preexist_location = NULL;
    char *postexist_location = NULL;
    int replace_count = 0;
    int size_required;
    int size_difference;
    int source_length;
    int searchfor_length;
    int replacewith_length;
    int segment_ok;

    if (replace_details->source == NULL)
    {
        return NULL;
    }

    source_length = (int)strlen( replace_details->source );
    source_end = replace_details->source + source_length;
    searchfor_length = (int)strlen(replace_details->searchfor);
    replacewith_length = (int)strlen(replace_details->replacewith);
    size_difference = replacewith_length - searchfor_length;
    size_required = source_length;
    replace_count = replace_details->replacenumber;

    if ((replace_details->preexist != NULL) && (strlen(replace_details->preexist) < 1))
    {
        replace_details->preexist = NULL;
    }
    if ((replace_details->postexist != NULL) && (strlen(replace_details->postexist) < 1))
    {
        replace_details->postexist = NULL;
    }

    /* If we have a 'pre-exist' request, then we need to check this out first*/
    /*		because if the pre-exist string cannot be found, then there's very*/
    /*		little point us continuing on in our search ( because without the*/
    /*		preexist string existing, we are thus not qualified to replace anything )*/
    if (replace_details->preexist != NULL)
    {
        preexist_location = PLD_strstr(replace_details->source, replace_details->preexist, replace_details->insensitive);
        if (preexist_location == NULL)
        {
            return replace_details->source;
        }
    }

    /* Determine if initial POSTexist tests will pass, if we don't pick up*/
    /*		anything here, then there's no point in continuing either*/
    if (replace_details->postexist != NULL)
    {
        char *p = replace_details->source;
        postexist_location = NULL;
        do
        {
            p = PLD_strstr(p, replace_details->postexist, replace_details->insensitive);
            if (p != NULL)
            {
                postexist_location = p;
                p = p + strlen(replace_details->postexist);
            }
        }
        while (p != NULL);

        if (postexist_location == NULL)
        {
            return replace_details->source;
        }
    }


    /* Step 1 - determine the MAXIMUM number of times we might have to replace this string ( or the limit*/
    /*		set by replacenumber*/
    /**/
    /*	Note - we only need this number if the string we're going to be inserting into the */
    /*	source is larger than the one we're replacing - this is so that we can ensure that*/
    /*	we have sufficient memory available in the buffer.*/
    if (size_difference > 0)
    {
        if (replace_count == 0)
        {
            char *p, *q;

            p = replace_details->source;
            q = PLD_strstr(p, replace_details->searchfor, replace_details->insensitive);
            while (q != NULL)
            {
                replace_count++;
                /*size_required += size_difference;*/
                p = q + searchfor_length;
                q = PLD_strstr(p, replace_details->searchfor, replace_details->insensitive);
            }

        }
        size_required = source_length + (size_difference * replace_count) + 1;
    }
    else
    {
        size_required = source_length + 1;
    }


    /* Allocate the memory required to hold the new string [at least], check to see that*/
    /*		all went well, if not, then return an error*/
    new_buffer = MALLOC( sizeof(char) * size_required);
    if (new_buffer == NULL)
    {
        LOGGER_log(_("%s:%d:PLD_strreplace:ERROR: Cannot allocate %d bytes of memory to perform replacement operation"), FL, size_required);
        return replace_details->source;
    }

    /* Our segment must always start at the beginning of the source, */
    /*		on the other hand, the segment_end can be anything from the*/
    /*		next byte to NULL ( which is specially treated to mean to */
    /*		the end of the source )*/
    segment_start = replace_details->source;


    /* Locate the first segment */
    segment_ok = 0;
    segment_end = PLD_strstr(replace_details->source, replace_details->searchfor, replace_details->insensitive);

    /* Determine if the first segment is valid in the presence of the */
    /*	pre-exist and post-exist requirements*/
    while ((segment_end != NULL) && (segment_ok == 0)\
            && ((replace_details->preexist != NULL) || (replace_details->postexist != NULL)))
    {
        int pre_ok = 0;
        int post_ok = 0;

        /* The PREexist test assumes a couple of factors - please ensure these are*/
        /*		relevant if you change any code prior to this point.*/
        /*	*/
        /*	1. preexist_location has already been computed and is not NULL*/
        /**/
        /*	2. By relative position, the first preexist_location will be a valid location*/
        /*			on which to validate for ALL replacements beyond that point, thus, we*/
        /*			never actually have to recompute preexist_location again.*/
        /**/
        /* 3. Conversely, the last computed postexist_location is valid for all */
        /*			matches before it*/
        /**/
        if (preexist_location == NULL)
        {
            pre_ok = 1;
        }
        else if (preexist_location < segment_end)
        {
            pre_ok = 1;
        }

        if (postexist_location == NULL)
        {
            post_ok = 1;
        }
        else if (postexist_location > segment_end)
        {
            post_ok = 1;
        }

        if ((pre_ok == 0) || (post_ok == 0))
        {
            segment_end = PLD_strstr(segment_end + searchfor_length, replace_details->searchfor, replace_details->insensitive);
        }
        else
        {
            segment_ok = 1;
        }
    }

    segment_p = segment_start;
    new_p = new_buffer;
    while (segment_start != NULL)
    {
        int replacewith_count;
        char *replacewith_p;

        if (segment_end == NULL)
        {
            segment_end = source_end;
        }

        replace_count--;

        /* Perform the segment copy*/
        segment_p = segment_start;
        while ((segment_p < segment_end) && (size_required > 0))
        {
            *new_p = *segment_p;
            new_p++;
            segment_p++;
            size_required--;
        }

        /* Perform the string replacement*/
        if (segment_end < source_end)
        {
            replacewith_count = replacewith_length;
            replacewith_p = replace_details->replacewith;
            while ((replacewith_count--) && (size_required > 0))
            {
                *new_p = *replacewith_p;
                new_p++;
                replacewith_p++;
                size_required--;
            }
        }

        if (size_required < 1 )
        {
            LOGGER_log(_("%s:%d:PLD_strreplace_general: Allocated memory ran out while replacing '%s' with '%s'"), FL, replace_details->searchfor, replace_details->replacewith);
            *new_p = '\0';
            break;
        }

        /* Find the next segment*/
        segment_start = segment_end + searchfor_length;

        /* If we've reached the end of the number of replacements we're supposed*/
        /*		to do, then we prepare the termination of the while loop by setting*/
        /*		our segment end to the end of the source.*/
        /**/
        /* NOTE: Remember that the replace_count is pre-decremented at the start*/
        /*		of the while loop, so, if the caller requested '0' replacements*/
        /*		this will now be -1, thus, it won't get terminated from this == 0*/
        /*		match.  Just thought you'd like to be reminded of that incase you*/
        /*		were wondering "Huh? this would terminate an unlimited replacement"*/
        if (replace_count == 0)
        {
            segment_end = NULL;
        }
        else
        {
            /* If our new segment to copy starts after the*/
            /*		end of the source, then we actually have */
            /*		nothing else to copy, thus, we prepare the*/
            /*		segment_start varible to cause the while loop */
            /*		to terminate.*/
            /**/
            /* Otherwise, we try and locate the next segment*/
            /*		ending point, and set the starting point to*/
            /*		be on the 'other side' of the 'searchfor' string*/
            /*		which we found in the last search.*/
            /**/
            if (segment_start > source_end)
            {
                segment_start = NULL;
            }
            else
            {

                /* Try find the next segment*/
                segment_ok = 0;
                segment_end = PLD_strstr(segment_end + searchfor_length, replace_details->searchfor, replace_details->insensitive);

                /* If we have a pre/post-exist requirement, then enter into this*/
                /*		series of tests.  NOTE - at least one of the pre or post tests*/
                /*		must fire to give an meaningful result - else we'll end up with */
                /*		a loop which simply goes to the end of the searchspace buffer*/
                while ((segment_end != NULL) && (segment_ok == 0)\
                        && ((replace_details->preexist != NULL) || (replace_details->postexist != NULL)))
                {
                    int pre_ok = 0;
                    int post_ok = 0;

                    /* The PREexist test assumes a couple of factors - please ensure these are*/
                    /*		relevant if you change any code prior to this point.*/
                    /*	*/
                    /*	1. preexist_location has already been computed and is not NULL*/
                    /**/
                    /*	2. By relative position, the first preexist_location will be a valid location*/
                    /*			on which to validate for ALL replacements beyond that point, thus, we*/
                    /*			never actually have to recompute preexist_location again.*/
                    /**/
                    /* 3. Conversely, the last computed postexist_location is valid for all */
                    /*			matches before it*/
                    /**/
                    if (preexist_location == NULL)
                    {
                        pre_ok = 1;
                    }
                    else if (preexist_location < segment_end)
                    {
                        pre_ok = 1;
                    }

                    if (postexist_location == NULL)
                    {
                        post_ok = 1;
                    }
                    else if (postexist_location > segment_end)
                    {
                        post_ok = 1;
                    }

                    if ((pre_ok == 0) || (post_ok == 0))
                    {
                        segment_end = PLD_strstr(segment_end + searchfor_length, replace_details->searchfor, replace_details->insensitive);
                    }
                    else
                    {
                        segment_ok = 1;
                    }
                }

            } /* If-else segment_start > source_end*/

        }

    }

    *new_p = '\0';

    if (replace_details->source != NULL)
    {
        FREE (replace_details->source);
    }
    replace_details->source = new_buffer;
    return new_buffer;
}
/*-----------------------------------------------------------------\
 Function Name	: main
 Returns Type	: int
 	----Parameter List
	1. int argc, 
	2.  char **argv, 
 	------------------
 Exit Codes	: 
 Side Effects	: 
--------------------------------------------------------------------
 Comments:
 
--------------------------------------------------------------------
 Changes:
 
\------------------------------------------------------------------*/
int main (int argc, char **argv)
{
	struct RIPMIME_globals glb;
	int result = 0;

	/* if the user has just typed in "ripmime" and nothing else, then we had better give them
	 * the rundown on how to use this program */

	if (argc < 2)
	{
		fprintf (stderr, "%s\n%s", version, help);
		return RIPMIME_ERROR_INSUFFICIENT_PARAMETERS;
	}

	// Set the global pointer ripmime_globals to point to
	//		the glb struct, so that if we have a timeout condition
	//		we can use the data
	ripmime_globals = &glb;


	// Set up our initial logging mode - so that we can always get
	//              report messages if need be.

	LOGGER_set_output_mode (_LOGGER_STDOUT);

	// Perform system initialisations

	MIME_init ();
	RIPMIME_init (&glb);

	// Setup our default behaviours */

	MIME_set_uniquenames (1);
	MIME_set_paranoid (0);
	MIME_set_header_longsearch(1); // 20040310-0117:PLD - Added by default as it seems stable, use --disable-qmail-bounce to turn off
	MIME_set_renamemethod (_MIME_RENAME_METHOD_INFIX);


	RIPMIME_parse_parameters (&glb, argc, argv);


	// if our input filename wasn't specified, then we better let the user know!
	if (!glb.inputfile)
	{
		LOGGER_log("Error: No input file was specified\n");
		return RIPMIME_ERROR_NO_INPUT_FILE;
	}

	// Fire up the randomizer

	srand (time (NULL));

	// clean up the output directory name if required (remove any trailing /'s, as suggested by James Cownie 03/02/2001

	if (glb.dir[strlen (glb.dir) - 1] == '/')
	{
		glb.dir[strlen (glb.dir) - 1] = '\0';
	}

	// Create the output directory required as specified by the -d parameter

	if (glb.dir != defaultdir)
	{
		result = mkdir (glb.dir, S_IRWXU);

		// if we had a problem creating a directory, and it wasn't just
		// due to the directory already existing, then we have a bit of
		// a problem on our hands, hence, report it.
		//

		if ((result == -1) && (errno != EEXIST))
		{
			LOGGER_log("ripMIME: Cannot create directory '%s' (%s)\n",
					glb.dir, strerror (errno));

			return RIPMIME_ERROR_CANT_CREATE_OUTPUT_DIR;
		}
	}

	// Unpack the contents
	RIPMIME_unpack(&glb);



	// Possible exit codes include;
	//		0 - all okay
	//		240 - processing stopped due to recursion limit

	if (glb.use_return_codes == 0) result = 0;

	return result;

}
/*-----------------------------------------------------------------\
 Function Name	: RIPMIME_signal_alarm
 Returns Type	: void
 	----Parameter List
	1. int sig , 
 	------------------
 Exit Codes	: 
 Side Effects	: 
--------------------------------------------------------------------
 Comments:
 
--------------------------------------------------------------------
 Changes:
 
\------------------------------------------------------------------*/
void RIPMIME_signal_alarm( int sig )
{
	if (ripmime_globals->quiet == 0) LOGGER_log("%s:%d:RIPMIME_signal_alarm: ripMIME took too long to complete. Mailpack is \"%s\", output dir is \"%s\"",FL, ripmime_globals->inputfile, ripmime_globals->dir );
	exit(RIPMIME_ERROR_TIMEOUT);
}
/*-----------------------------------------------------------------\
 Function Name	: RIPMIME_parse_parameters
 Returns Type	: int
 	----Parameter List
	1. struct RIPMIME_globals *glb, 
	2.  int argc, 
	3.  char **argv, 
 	------------------
 Exit Codes	: 
 Side Effects	: 
--------------------------------------------------------------------
 Comments:
 
--------------------------------------------------------------------
 Changes:
 
\------------------------------------------------------------------*/
int RIPMIME_parse_parameters (struct RIPMIME_globals *glb, int argc, char **argv)
{
	int i;
	int result = 0;

	MIME_set_filename_report_fn (RIPMIME_report_filename_decoded);

	for (i = 1; i < argc; i++)
	{
		// if the first char of the argument is a '-', then we possibly have a flag

		if (argv[i][0] == '-')
		{
			// test the 2nd char of the parameter

			switch (argv[i][1])
			{
				case 'i':
					if (argv[i][2] != '\0')
					{
						glb->inputfile = &argv[i][2];
					}
					else
					{
						i++;
						if (i < argc)
						{
							glb->inputfile = argv[i];
						}
						else
						{
							LOGGER_log("ERROR: insufficient parameters after '-i'\n");
						}
					}
					break;

				case 'd':
					if (argv[i][2] != '\0')
					{
						glb->dir = &(argv[i][2]);
					}
					else
					{
						i++;
						if (i < argc)
						{
							glb->dir = argv[i];
						}
						else
						{
							LOGGER_log("ERROR: insufficient parameters after '-d'\n");
						}
					}

					break;

				case 'p':
					if (argv[i][2] != '\0')
					{
						MIME_set_blankfileprefix (&argv[i][2]);
					}
					else
					{
						i++;
						if (i < argc)
						{
							MIME_set_blankfileprefix (argv[i]);
						}
						else
						{
							LOGGER_log("ERROR: insufficient parameters after '-p'\n");
						}
					}
					break;		// this is in mime.h

				case 'e':
					MIME_set_dumpheaders (1);
					if (argv[i][2] != '\0')
					{
						MIME_set_headersname (&argv[i][2]);
					}
					else
					{
						if ((i < (argc - 1)) && (argv[i + 1][0] != '-'))
							MIME_set_headersname (argv[++i]);
					}
					break;		// makes MIME dump out the headers to a file

				case 'x':
					if (argv[i][2] != '\0')
					{
						MIME_set_out_charset(&argv[i][2]);
					}
					else
					{
            LOGGER_log("ERROR: insufficient parameters after '-x'\n");
            abort();
					}
					break;
#ifdef RIPMIME_BLANKZONE
				case 'b':
					if (argv[i][2] != '\0')
					{
						MIME_set_blankzone_filename (&argv[i][2]);
					}
					else
					{
						if ((i < (argc - 1)) && (argv[i + 1][0] != '-'))
							MIME_set_blankzone_filename (argv[++i]);
					}
					break;		// blankzone storage option
#endif

				case 'v':
					MIME_set_verbosity (1);
					glb->verbose = 1;
					break;

				case 'q':
					glb->quiet = 1;
					MIME_set_quiet(glb->quiet);
					break;

				case 'V':
					fprintf (stdout, "%s\n", version);
					exit (1);
					break;
				case 'h':
					fprintf (stdout, "%s\n", help);
					exit (1);
					break;

					// if we get ANOTHER - symbol, then we have an extended flag

				case '-':
					if (strncmp (&(argv[i][2]), "verbose-contenttype", strlen ("verbose-contenttype")) == 0) {
						MIME_set_verbosity_contenttype (1);

					/** 20051117-0927:PLD: 
					 ** If client uses --verbose-mime, then make ripMIME report when it
					 ** detects a MIME encoded email **/
					} else if (strncmp(&(argv[i][2]), "verbose-mime", strlen("verbose-mime"))==0) {
						MIME_set_report_MIME(1);

					} else if (strncmp (&(argv[i][2]), "verbose-oldstyle", strlen ("verbose-oldstyle")) == 0) {
							MIME_set_verbosity_12x_style (1);
							MIME_set_filename_report_fn (NULL);
						}
						else if (strncmp (&(argv[i][2]), "verbose-defects",15) == 0)
						{
							glb->verbose_defects = 1;
							MIME_set_verbose_defects(1);
						}
						else if (strncmp (&(argv[i][2]), "paranoid", 8) == 0)
						{
							MIME_set_paranoid (1);
						}
						else if (strncmp (&(argv[i][2]), "no_paranoid", 11) == 0)
						{
							MIME_set_paranoid (0);
						}
						else if (strncmp (&(argv[i][2]), "no-paranoid", 11) == 0)
						{
							MIME_set_paranoid (0);
						}
						else if (strncmp (&(argv[i][2]), "prefix", 6) == 0)
						{
							MIME_set_renamemethod (_MIME_RENAME_METHOD_PREFIX);
						}
						else if (strncmp (&(argv[i][2]), "postfix", 7) == 0)
						{
							MIME_set_renamemethod (_MIME_RENAME_METHOD_POSTFIX);
						}
						else if (strncmp (&(argv[i][2]), "infix", 5) == 0)
						{
							MIME_set_renamemethod (_MIME_RENAME_METHOD_INFIX);
						}
						else if (strncmp (&(argv[i][2]), "overwrite", 9) == 0)
						{
							MIME_set_uniquenames (0);
						}
						else if (strncmp (&(argv[i][2]), "unique_names", 12) == 0)
						{
							MIME_set_uniquenames (1);
						}
						else if (strncmp (&(argv[i][2]), "unique-names", 12) == 0)
						{
							MIME_set_uniquenames (1);
						}
						else if (strncmp(&(argv[i][2]), "name-by-type", 12) == 0)
						{
							MIME_set_name_by_type(1);
						}
						else if (strncmp (&(argv[i][2]), "syslog", 9) == 0)
						{
							LOGGER_set_output_mode (_LOGGER_SYSLOG);
							LOGGER_set_syslog_mode (LOG_MAIL | LOG_INFO);
						}
						else if (strncmp (&(argv[i][2]), "stderr", 10) == 0)
						{
							LOGGER_set_output_mode (_LOGGER_STDERR);
						}
						else if (strncmp (&(argv[i][2]), "stdout", 9) == 0)
						{
							LOGGER_set_output_mode (_LOGGER_STDOUT);
						}
						else if (strncmp (&(argv[i][2]), "no_nameless", 11) == 0)
						{
							MIME_set_no_nameless (1);
						}
						else if (strncmp (&(argv[i][2]), "no-nameless", 11) == 0)
						{
							MIME_set_no_nameless (1);
						}
						else if (strncmp (&(argv[i][2]), "debug", 5) == 0)
						{
							MIME_set_debug (1);
						}
						else if (strncmp (&(argv[i][2]), "mailbox", 7) == 0)
						{
							MIME_set_mailboxformat (1);
						}
						else if (strncmp(&(argv[i][2]), "formdata", 8) == 0)
						{
							// Form data usually contains embedded \0 sequences
							//		so we need to explicitly turn this off.
							FFGET_set_allow_nul(1);
						}
						else if (strncmp (&(argv[i][2]), "no_uudecode", 11) == 0)
						{
							// We are transitioning away from negative-logic function
							//	names because they can cause confusion when reading, so
							// from here on, we will use things like _set_foo() rather
							// than _set_no_foo()

							MIME_set_decode_uudecode(0);
						}
						else if (strncmp (&(argv[i][2]), "no-uudecode", 11) == 0)
						{
							MIME_set_decode_uudecode(0);
						}
						else if (strncmp (&(argv[i][2]), "no-tnef", 7) == 0)
						{
							MIME_set_decode_tnef (0);
						}
						else if (strncmp (&(argv[i][2]), "no-ole", 6) == 0)
						{
							MIME_set_decode_ole(0);
						}
						else if (strncmp (&(argv[i][2]), "no-base64", 9) == 0)
						{
							MIME_set_decode_base64(0);
						}
						else if (strncmp (&(argv[i][2]), "no-quotedprintable", strlen("no-quotedprintable")) == 0) 
						{
							MIME_set_decode_qp(0);
						}
						else if (strncmp(&(argv[i][2]), "no-doublecr", strlen("no-doublecr")) == 0)
						{
							MIME_set_decode_doubleCR(0);
						}
						else if (strncmp(&(argv[i][2]), "no-mht", strlen("no-mht")) == 0)
						{
							MIME_set_decode_mht(0);
						}
					else if (strncmp(&(argv[i][2]), "disable-header-fix", strlen("disable-headerfix")) == 0) {
							MIMEH_set_headerfix(0);
					}
						else if (strncmp(&(argv[i][2]), "qmail-bounce", strlen("qmail-bounce")) == 0)
						{
							MIME_set_header_longsearch(1);
						}
						else if (strncmp(&(argv[i][2]), "disable-qmail-bounce", strlen("disable-qmail-bounce")) == 0)
						{
							MIME_set_header_longsearch(0);
						}
						else if (strncmp(&(argv[i][2]), "no-multiple-filenames", strlen("no-multiple-filenames")) == 0)
						{
							MIME_set_multiple_filenames(0);
						}
						else if (strncmp(&(argv[i][2]), "recursion-max", strlen("recursion-max")) == 0)
						{
							if (argv[i+1] != NULL)
							{
								int level;

								level = atoi(argv[i+1]);
								if (level > 0)
								{
									MIME_set_recursion_level(level);
								}
							}
						}
						else if (strncmp(&(argv[i][2]), "timeout", strlen("timeout")) == 0)
						{
							if (argv[i+1] != NULL)
							{
								int seconds;

								seconds = atoi(argv[i+1]);
								if (seconds > 0)
								{
									glb->timeout = seconds;
								}
							}
						}
						else if (strncmp (&(argv[i][2]), "buildcodes", 10) == 0)
						{
							fprintf(stdout,"%s\n%s\n%s\n", BUILD_CODE, BUILD_DATE, BUILD_BOX);
							exit(0);
						}
						else if (strncmp (&(argv[i][2]), "version", 7) == 0)
						{
							fprintf (stdout, "%s\n", version);
							exit (0);
						}
						else if (strncmp(&(argv[i][2]), "extended-errors", strlen("extended-errors")) == 0)
						{
							glb->use_return_codes = 1;
						}
						else
						{
							LOGGER_log ("Cannot interpret option \"%s\"\n%s\n", argv[i],
									help);
							exit (1);
							break;
						}
					break;

					// else, just dump out the help message

				default:
					LOGGER_log ("Cannot interpret option \"%s\"\n%s\n", argv[i],
							help);
					exit (1);
					break;

			}			// Switch argv[i][1]

		}			// if argv[i][0] == -

	}				// for

	return result;
}