/*
  $Id: smtp-convert.c 1550 2005-01-07 12:23:02Z paul $
 Copyright (C) 1999-2004 IC & S  dbmail@ic-s.nl

 This program is free software; you can redistribute it and/or 
 modify it under the terms of the GNU General Public License 
 as published by the Free Software Foundation; either 
 version 2 of the License, or (at your option) any later 
 version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/* 
 * this program traverses a directory tree and executes
 * dbmail conversion on each file.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <time.h>
#include <unistd.h>
#include "db.h"
#include "auth.h"
#include "dbmailtypes.h"
#include "debug.h"
#include <regex.h>

#define MAX_LINESIZE 1024
#define UID_SIZE 70

const char *mbox_delimiter_pattern = "^From .*  ";
char blk[READ_BLOCK_SIZE + MAX_LINESIZE + 1];

/* syslog */
#define PNAME "dbmail/uni-one-convertor"

char *getusername(char *path);
int traverse(char *path);
int process_mboxfile(char *file, u64_t userid);



int main(int argc, char *argv[])
{
	time_t start;
	time_t stop;
	int result;

	if (argc < 2) {
		printf("Error, traverse need a directory as argument\n");
		return -1;
	}

	openlog(PNAME, LOG_PID, LOG_MAIL);	/* open connection to syslog */
	configure_debug(TRACE_ERROR, 1, 0);

	/* open database connection */
	if (db_connect() != 0) {
		printf("Error opening database connection\n");
		return -1;
	}

	/* open authentication connection */
	if (auth_connect() != 0) {
		printf("Error opening authentication connection\n");
		return -1;
	}

	srand((int) ((int) time(NULL) + (int) getpid()));

	time(&start);		/* mark the starting time */
	result = traverse(argv[1]);
	time(&stop);		/* mark the ending time */

	printf("Conversion started @  %s", ctime(&start));
	printf("Conversion finished @ %s", ctime(&stop));

	return result;
}



char *getusername(char *path)
{
	int i;
	char *tmp;

	i = strlen(path);
	tmp = path + i;

	while ((tmp != path) && (*tmp != '/'))
		tmp--;

	return tmp + 1;
}


int traverse(char *path)
{
	char newpath[1024];
	char *username;
	struct dirent **namelist;
	int n;
	u64_t userid;

	n = scandir(path, &namelist, 0, alphasort);

	if (n < 0) {
		printf("file %s\n", path);
		username = getusername(path);
		printf("username %s\n", username);

		printf("creating user...");
		userid = auth_adduser(username, "default", "", "0", "10M");
		if (userid != -1 && userid != 0) {
			printf("Ok id [%llu]\n", userid);
			printf("converting mailbox...");
			fflush(stdout);
			n = process_mboxfile(path, userid);
			if (n != 0)
				printf
				    ("Warning: error converting mailbox\n");
			else
				printf("done :)\n");
		} else {
			printf("user already exists. Skipping\n");
		}

	} else {
		while (n--) {
			if ((strcmp(namelist[n]->d_name, "..") != 0) &&
			    (strcmp(namelist[n]->d_name, ".") != 0)) {
				sprintf(newpath, "%s/%s", path,
					namelist[n]->d_name);
				traverse(newpath);
			}
			dm_free(namelist[n]);
		}
		dm_free(namelist);
	}
	return 0;
}


int process_mboxfile(char *file, u64_t userid)
{
	regex_t preg;
	int result;
	FILE *infile;
	int in_msg, header_passed;
	char newunique[UID_SIZE];
	unsigned cnt, len, newlines;
	u64_t msgid = 0, size;
	char saved;

	if ((result =
	     regcomp(&preg, mbox_delimiter_pattern, REG_NOSUB)) != 0) {
		trace(TRACE_ERROR, "Regex compilation failed.");
		return -1;
	}

	if ((infile = fopen(file, "r")) == 0) {

		trace(TRACE_ERROR, "Could not open file [%s]", infile);
		return -1;
	}

	in_msg = 0;
	cnt = 0;
	size = 0;
	newlines = 0;

	while (!feof(infile) && !ferror(infile)) {
		if (fgets(&blk[cnt], MAX_LINESIZE, infile) == 0)
			break;

		/* check if this is an mbox delimiter */
		if (regexec(&preg, &blk[cnt], 0, NULL, 0) == 0) {
			if (!in_msg)
				in_msg = 1;	/* ok start of a new msg */
			else {
				/* update & end message */
				db_insert_message_block(blk, cnt, msgid,BODY_BLOCK);

				create_unique_id(newunique, msgid);
				db_update_message(msgid, newunique,
						  size + cnt,
						  size + cnt + newlines);
				trace(TRACE_ERROR,
				      "message [%llu] inserted, [%u] bytes",
				      msgid, size + cnt);
			}

			/* start new message */
			msgid =
			    db_insert_message(userid, 0,
					      ERROR_IF_MBOX_NOT_FOUND, 0);
			header_passed = 0;
			cnt = 0;
			size = 0;
			newlines = 0;
		} else {
			newlines++;
			if (header_passed == 0) {
				/* we're still reading the header */
				len = strlen(&blk[cnt]);
				if (strcmp(&blk[cnt], "\n") == 0) {
					db_insert_message_block(blk, cnt + len, msgid,HEAD_BLOCK);
					header_passed = 1;
					size += (cnt + len);
					cnt = 0;
				} else
					cnt += len;
			} else {
				/* this is body data */
				len = strlen(&blk[cnt]);
				cnt += len;

				if (cnt >= READ_BLOCK_SIZE) {
					/* write block */
					saved = blk[READ_BLOCK_SIZE];

					blk[READ_BLOCK_SIZE] = '\0';
					db_insert_message_block(blk, READ_BLOCK_SIZE, msgid,BODY_BLOCK);
					blk[READ_BLOCK_SIZE] = saved;

					memmove(blk, &blk[READ_BLOCK_SIZE],
						cnt - (READ_BLOCK_SIZE));
					size += READ_BLOCK_SIZE;
					cnt -= READ_BLOCK_SIZE;
				}
			}
		}
	}

	/* update & end message */
	if (msgid > 0) {
		db_insert_message_block(blk, cnt, msgid,BODY_BLOCK);

		create_unique_id(newunique, msgid);
		db_update_message(msgid, newunique, size + cnt,
				  size + cnt + newlines);
		trace(TRACE_ERROR, "message [%llu] inserted, [%u] bytes",
		      msgid, size + cnt);
	}

	fclose(infile);
	return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1