/*----------------------------------------
 * ripMIME -
 *
 * Written by Paul L Daniels
 * pldaniels@pldaniels.com
 *
 * (C)2001 P.L.Daniels
 * http://www.pldaniels.com/ripmime
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <syslog.h>

#include "logger.h"
#include "ffget.h"
#include "mime.h"
#include "MIME_headers.h"

struct RIPMIME_globals
{
	char *inputfile;
	char *dir;
};

//-b [blankzone file name] : Dump the contents of the MIME blankzone to 'filename'

char defaultdir[] = ".";
char version[] = "v1.3.0.5 - 23/10/2003 (C) PLDaniels http://www.pldaniels.com/ripmime";
char help[] = "ripMIME -i <mime file> -d <directory>\
	[-p prefix] [-e [header file]] [-vVh] [--version]\
	[--syslog_on] [--stderr_off]\
	[--no_nameless] [--unique_names [--prefix|--postfix|--infix]]\
	[--paranoid] [--mailbox] [--debug]\
	[--no-tnef] [--no-quotedprintable] [--no-uudecode]\n\
Options available :\n\
	-i : Input MIME encoded file (use '-' to input from STDIN)\n\
	-d : Output directory\n\
	-p : Specify prefix filename to be used on files without a filename (default 'text')\n\
	-e [headers file name] : Dump headers from mailpack (default '_headers_')\n\
	-v : Turn on verbosity\n\
	-q : Run quietly, do no report non-fatal errors\n\
	--verbose-contenttype : Turn on verbosity of file content type\n\
	--verbose-oldstyle : Uses the v1.2.x style or filename reporting\n\
	--stdout : All reporting goes to stdout (Default)\n\
	--stderr : All reporting goes to stderr\n\
	--syslog : All reporting goes to syslog\n\
	--no-paranoid : [ Deprecated ] Turns off strict ascii-alnum filenaming\n\
	--paranoid: Converts all filenames to strict 7-bit compliance\n\
	--name-by-type: Saves a given attachment by its content-type if it has no other name\n\
	--no-nameless : Do not save nameless attachments\n\
	--overwrite : Overwrite files if they have the same name on extraction\n\
	--unique-names : Dont overwrite existing files (This is the default behaviour)\n\
	--prefix : rename by putting unique code at the front of the filename\n\
	--postfix : rename by putting unique code at the end of the filename\n\
	--infix : rename by putting unique code in the middle of the filename\n\
	--mailbox : Process mailbox file\n\
	--debug : Produces detailed information about the whole decoding process\n\
	--no-tnef : Turn off TNEF/winmail.dat decoding\n\
	--no-ole : Turn off OLE decoding\n\
	--no-uudecode : Turns off the facility of detecting UUencoded attachments in emails\n\
	--no-quotedprintable : Turns off the facility of decoding QuotedPrintable data\n\
	--no-doublecr : Turns off saving of double-CR embedded data\n\
	--no-mht : Turns off MHT (a Microsoft mailpack attachment format ) decoding\n\
	-V --version : Give version information\n\
	-h : This message (help)\n\n\n";

/*-----------------------------------------------------------------\
 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;
}



/*-----------------------------------------------------------------\
 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
#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);
					break;

				case 'q':
					MIME_set_quiet(1);
					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);
					}
					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]), "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]), "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]), "version", 7) == 0)
						{
							fprintf (stdout, "%s\n", version);
							exit (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;
}



/*-----------------------------------------------------------------\
 Function Name	: RIPMIME_init
 Returns Type	: int
 	----Parameter List
	1. struct RIPMIME_globals *glb, 
 	------------------
 Exit Codes	: 
 Side Effects	: 
--------------------------------------------------------------------
 Comments:
 
--------------------------------------------------------------------
 Changes:
 
\------------------------------------------------------------------*/
int RIPMIME_init (struct RIPMIME_globals *glb)
{
	glb->dir = defaultdir;
	glb->inputfile = NULL;


	return 0;
}


/*-----------------------------------------------------------------\
 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);
		exit (1);
	}

	// 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_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)
	{
		fprintf (stderr, "Error: No input file was specified\n");
		exit (1);
	}

	// 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))
		{
			fprintf (stderr, "ripMIME: Cannot create directory '%s' (%s)\n",
					glb.dir, strerror (errno));
			return -1;
		}
	}

	// Unpack the contents

	MIMEH_set_outputdir (glb.dir);
	MIME_unpack (glb.dir, glb.inputfile, 0);

	// do any last minute things

	MIME_close ();

	return 0;

}

/*-END-----------------------------------------------------------*/
