changeset 39:2ad7ef0a3c4f stable-0-5-10

more valgrind fixes
author carl
date Mon, 20 Aug 2007 20:43:17 -0700
parents f5c024aa1dc5
children be6d5329cc01
files ChangeLog NEWS configure.in src/libpst.c src/libpst.h src/readpst.c
diffstat 6 files changed, 331 insertions(+), 445 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sun Aug 12 14:30:15 2007 -0700
+++ b/ChangeLog	Mon Aug 20 20:43:17 2007 -0700
@@ -1,3 +1,11 @@
+LibPST 0.5.10 (2007-08-20)
+===============================
+
+        * fix yet more valgrind errors - finally have a clean memory check.
+        * restructure readpst.c for proper recursive tree walk.
+        * buffer overrun test was backwards, introduced at 0.5.6
+        * fix broken email attachments, introduced at 0.5.6
+
 LibPST 0.5.9 (2007-08-12)
 ===============================
 
--- a/NEWS	Sun Aug 12 14:30:15 2007 -0700
+++ b/NEWS	Mon Aug 20 20:43:17 2007 -0700
@@ -1,10 +1,11 @@
     $Id$
 
-0.5.9 2007-08-12 fix more valgrind errors, pst2ldif wrote undefined data
-0.5.8 2007-08-10 lzfu_decompress/base64_encode encoded random data into attachment
-0.5.7 2007-08-09 fix valgrind errors, using uninitialized data
-0.5.6 2007-07-15 handle small pst files, better decoding of 7c blocks
-0.5.5 2007-07-10 merge changes from Joe Nahmias version
-0.5.4 2006-02-25 add MH mode, generated filenames with no leading zeros
-0.5.3 2006-02-20 switch to gnu autoconf/automake
-0.5.2 2006-02-18 add pst2ldif, fix btree processing in libpst.c
+0.5.10  2007-08-20 fix yet more valgrind errors, restructure readpst recursive walk, backwards overrun test
+0.5.9   2007-08-12 fix more valgrind errors, pst2ldif wrote undefined data
+0.5.8   2007-08-10 lzfu_decompress/base64_encode encoded random data into attachment
+0.5.7   2007-08-09 fix valgrind errors, using uninitialized data
+0.5.6   2007-07-15 handle small pst files, better decoding of 7c blocks
+0.5.5   2007-07-10 merge changes from Joe Nahmias version
+0.5.4   2006-02-25 add MH mode, generated filenames with no leading zeros
+0.5.3   2006-02-20 switch to gnu autoconf/automake
+0.5.2   2006-02-18 add pst2ldif, fix btree processing in libpst.c
--- a/configure.in	Sun Aug 12 14:30:15 2007 -0700
+++ b/configure.in	Mon Aug 20 20:43:17 2007 -0700
@@ -1,7 +1,7 @@
 AC_INIT(configure.in)
 
 AM_CONFIG_HEADER(config.h)
-AM_INIT_AUTOMAKE(libpst,0.5.9)
+AM_INIT_AUTOMAKE(libpst,0.5.10)
 AC_PATH_PROGS(BASH, bash)
 
 AC_LANG_CPLUSPLUS
--- a/src/libpst.c	Sun Aug 12 14:30:15 2007 -0700
+++ b/src/libpst.c	Mon Aug 20 20:43:17 2007 -0700
@@ -266,7 +266,10 @@
 			size = _pst_ff_getID2data(pf, ptr, &h);
 			// will need to encode any bytes left over
 			c = base64_encode(h.base64_extra_chars, h.base64_extra);
-			if (c) pst_fwrite(c, 1, strlen(c), fp);
+			if (c) {
+				pst_fwrite(c, 1, strlen(c), fp);
+				free(c);	// caught by valgrind
+			}
 		} else {
 			DEBUG_WARN (("Couldn't find ID pointer. Cannot save attachement to Base64\n"));
 			size = 0;
@@ -275,7 +278,10 @@
 	} else {
 		// encode the attachment to the file
 		c = base64_encode(attach->data, attach->size);
-		if (c) pst_fwrite(c, 1, strlen(c), fp);
+		if (c) {
+			pst_fwrite(c, 1, strlen(c), fp);
+			free(c);	// caught by valgrind
+		}
 		size = attach->size;
 	}
 	DEBUG_RET();
@@ -954,17 +960,16 @@
 	item = (pst_item*) xmalloc(sizeof(pst_item));
 	memset(item, 0, sizeof(pst_item));
 
-	if (_pst_process(list, item)) {
+	if (_pst_process(list, item, NULL)) {
 		DEBUG_WARN(("_pst_process() returned non-zero value. That is an error\n"));
-		if (item)	  free(item);
+		if (item)	  _pst_freeItem(item);
 		if (list)	  _pst_free_list(list);
 		if (id2_head) _pst_free_id2(id2_head);
 		DEBUG_RET();
 		return NULL;
-	} else {
-		if (list) _pst_free_list(list);
-		list = NULL; //_pst_process will free the items in the list
 	}
+	if (list) _pst_free_list(list);
+	list = NULL; //_pst_process will free the items in the list
 
 	if ((id_ptr = _pst_getID2(id2_head, 0x671))) {
 		// attachements exist - so we will process them
@@ -977,7 +982,7 @@
 		DEBUG_EMAIL(("ATTACHEMENT processing attachement\n"));
 		if ((list = _pst_parse_block(pf, id_ptr->id, id2_head)) == NULL) {
 			DEBUG_WARN(("ERROR error processing main attachment record\n"));
-			if (item) free(item);
+			if (item) _pst_freeItem(item);
 			if (id2_head) _pst_free_id2(id2_head);
 			DEBUG_RET();
 			return NULL;
@@ -992,9 +997,9 @@
 				x++;
 			}
 
-			if (_pst_process(list, item)) {
+			if (_pst_process(list, item, item->attach)) {
 				DEBUG_WARN(("ERROR _pst_process() failed with attachments\n"));
-				if (item)	  free(item);
+				if (item)	  _pst_freeItem(item);
 				if (list)	  _pst_free_list(list);
 				if (id2_head) _pst_free_id2(id2_head);
 				DEBUG_RET();
@@ -1017,7 +1022,7 @@
 					  attach = attach->next;
 					  continue;
 				  }
-				  if (_pst_process(list, item)) {
+				  if (_pst_process(list, item, attach)) {
 					  DEBUG_WARN(("ERROR _pst_process() failed with an attachment\n"));
 					  if (list) _pst_free_list(list);
 					  list = NULL;
@@ -1026,7 +1031,8 @@
 				  }
 				  if (list) _pst_free_list(list);
 				  list = NULL;
-				  if ((id_ptr = _pst_getID2(id2_head, attach->id2_val))) {
+				  id_ptr = _pst_getID2(id2_head, attach->id2_val);
+				  if (id_ptr) {
 					  // id2_val has been updated to the ID2 value of the datablock containing the
 					  // attachment data
 					  attach->id_val = id_ptr->id;
@@ -1290,6 +1296,7 @@
 		// allocate an array of count num_recs to contain sizeof(struct_pst_num_item)
 		na_ptr->items		= (struct _pst_num_item**) xmalloc(sizeof(struct _pst_num_item)*num_list);
 		na_ptr->count_item	= num_list;
+		na_ptr->orig_count	= num_list;
 		na_ptr->count_array = num_recs; // each record will have a record of the total number of records
 		for (x=0; x<num_list; x++) na_ptr->items[x] = NULL;
 		x = 0;
@@ -1316,10 +1323,10 @@
 				// table_rec and table2_rec are arranged differently, so assign the values across
 				table_rec.type	   = table2_rec.type;
 				table_rec.ref_type = table2_rec.ref_type;
-				if ((ind2_end - ind2_ptr) <= (table2_rec.ind2_off + table2_rec.size)) {
+				table_rec.value    = 0;
+				if ((ind2_end - ind2_ptr) >= (table2_rec.ind2_off + table2_rec.size)) {
 					int n = table2_rec.size;
 					int m = sizeof(table_rec.value);
-					table_rec.value = 0;
 					if (n <= m) {
 						memcpy(&table_rec.value, ind2_ptr + table2_rec.ind2_off, n);
 					}
@@ -1344,7 +1351,9 @@
 			DEBUG_EMAIL(("reading block %i (type=%#x, ref_type=%#x, value=%#x)\n",
 				x, table_rec.type, table_rec.ref_type, table_rec.value));
 
-			na_ptr->items[x] = (struct _pst_num_item*) xmalloc(sizeof(struct _pst_num_item));
+			if (!na_ptr->items[x]) {
+				na_ptr->items[x] = (struct _pst_num_item*) xmalloc(sizeof(struct _pst_num_item));
+			}
 			memset(na_ptr->items[x], 0, sizeof(struct _pst_num_item)); //init it
 
 			// check here to see if the id of the attribute is a mapped one
@@ -1416,11 +1425,19 @@
 					memcpy(na_ptr->items[x]->data, value_pointer, value_size);
 				}
 				else if (_pst_getBlockOffsetPointer(pf, i2_head, buf, read_size, ind_ptr, table_rec.value, &block_offset7)) {
-					if (table_rec.value) {
-						DEBUG_WARN(("failed to get block offset for table_rec.value of %#x\n", table_rec.value));
+					if ((table_rec.value & 0xf) == 0xf) {
+						DEBUG_WARN(("failed to get block offset for table_rec.value of %#x to be read later.\n", table_rec.value));
+						na_ptr->items[x]->size = 0;
+						na_ptr->items[x]->data = NULL;
+						na_ptr->items[x]->type = table_rec.value;
 					}
-					na_ptr->count_item --; //we will be skipping a row
-					continue;
+					else {
+						if (table_rec.value) {
+							DEBUG_WARN(("failed to get block offset for table_rec.value of %#x\n", table_rec.value));
+						}
+						na_ptr->count_item --; //we will be skipping a row
+						continue;
+					}
 				}
 				else {
 					value_size = block_offset7.to - block_offset7.from;
@@ -1434,13 +1451,12 @@
 					// there is still more to do for the type of 0xD
 					type_d_rec = (struct _type_d_rec*) na_ptr->items[x]->data;
 					LE32_CPU(type_d_rec->id);
-					if ((na_ptr->items[x]->size = _pst_ff_getID2block(pf, type_d_rec->id, i2_head, &(na_ptr->items[x]->data)))==0){
-						DEBUG_WARN(("not able to read the ID2 data. Setting to be read later. %#x\n",
-						  type_d_rec->id));
+					na_ptr->items[x]->size = _pst_ff_getID2block(pf, type_d_rec->id, i2_head, &(na_ptr->items[x]->data));
+					if (!na_ptr->items[x]->size){
+						DEBUG_WARN(("not able to read the ID2 data. Setting to be read later. %#x\n", type_d_rec->id));
+						na_ptr->items[x]->type = type_d_rec->id;	// fetch before freeing data, alias pointer
 						free(na_ptr->items[x]->data);
-						na_ptr->items[x]->size = 0;
 						na_ptr->items[x]->data = NULL;
-						na_ptr->items[x]->type = type_d_rec->id;
 					}
 				}
 				if (na_ptr->items[x]->type == 0) na_ptr->items[x]->type = table_rec.ref_type;
@@ -1494,10 +1510,9 @@
 }
 
 
-int32_t _pst_process(pst_num_array *list , pst_item *item) {
+int32_t _pst_process(pst_num_array *list , pst_item *item, pst_item_attach *attach) {
 	int32_t x, t;
 	int32_t next = 0;
-	pst_item_attach *attach;
 	pst_item_extra_field *ef;
 
 	DEBUG_ENT("_pst_process");
@@ -1507,8 +1522,6 @@
 		return -1;
 	}
 
-	   attach = item->attach; // a working variable
-
 	while (list) {
 		x = 0;
 		while (x < list->count_item) {
@@ -3101,16 +3114,13 @@
 	pst_num_array *l;
 	DEBUG_ENT("_pst_free_list");
 	while (list) {
-		int32_t x = 0;
 		if (list->items) {
-			while (x < list->count_item) {
+			int32_t x;
+			for (x=0; x < list->orig_count; x++) {
 				if (list->items[x]) {
-					if (list->items[x]->data) {
-						free (list->items[x]->data);
-					}
-					free (list->items[x]);
+					if (list->items[x]->data) free(list->items[x]->data);
+					free(list->items[x]);
 				}
-				x++;
 			}
 			free(list->items);
 		}
@@ -3877,7 +3887,7 @@
 size_t _pst_ff_getID2block(pst_file *pf, u_int32_t id2, pst_index2_ll *id2_head, unsigned char** buf) {
 	pst_index_ll* ptr;
 	//	size_t ret;
-	struct holder h = {buf, NULL, 0};
+	struct holder h = {buf, NULL, 0, "", 0};
 	DEBUG_ENT("_pst_ff_getID2block");
 	ptr = _pst_getID2(id2_head, id2);
 
@@ -3892,7 +3902,6 @@
 
 
 size_t _pst_ff_getID2data(pst_file *pf, pst_index_ll *ptr, struct holder *h) {
-	// if the attachment begins with 01 01, <= 256 bytes, it is stored in the record
 	int32_t ret;
 	unsigned char *b = NULL, *t;
 	DEBUG_ENT("_pst_ff_getID2data");
@@ -3902,15 +3911,15 @@
 			*(h->buf) = b;
 		} else if ((h->base64 == 1) && h->fp) {
 			t = base64_encode(b, ret);
-			if (t) pst_fwrite(t, 1, strlen(t), h->fp);
+			if (t) {
+				pst_fwrite(t, 1, strlen(t), h->fp);
+				free(t);	// caught by valgrind
+			}
 			free(b);
 		} else if (h->fp) {
 			pst_fwrite(b, 1, ret, h->fp);
 			free(b);
 		}
-		//if ((*buf)[0] == 0x1) {
-		//	  DEBUG_WARN(("WARNING: buffer starts with 0x1, but I didn't expect it to!\n"));
-		//}
 	} else {
 		// here we will assume it is a block that points to others
 		DEBUG_READ(("Assuming it is a multi-block record because of it's id\n"));
@@ -3931,7 +3940,8 @@
 	unsigned char fdepth;
 
 	DEBUG_ENT("_pst_ff_compile_ID");
-	if ((a = _pst_ff_getIDblock(pf, id, &buf3))==0) {
+	a = _pst_ff_getIDblock(pf, id, &buf3);
+	if (!a) {
 		if (buf3) free(buf3);
 		return 0;
 	}
@@ -3944,7 +3954,10 @@
 			*(h->buf) = buf3;
 		else if (h->base64 == 1 && h->fp) {
 			t = base64_encode(buf3, a);
-			if (t) pst_fwrite(t, 1, strlen(t), h->fp);
+			if (t) {
+				pst_fwrite(t, 1, strlen(t), h->fp);
+				free(t);	// caught by valgrind
+			}
 			free(buf3);
 		} else if (h->fp) {
 			pst_fwrite(buf3, 1, a, h->fp);
@@ -3988,9 +4001,11 @@
 				memcpy(h->base64_extra_chars, &(buf2[z-b]), b);
 				h->base64_extra = b;
 				t = base64_encode(buf2, z-b);
-				if (t) pst_fwrite(t, 1, strlen(t), h->fp);
-				DEBUG_READ(("writing %i bytes to file as base64 [%i]. Currently %i\n",
-						z, strlen(t), size));
+				if (t) {
+					DEBUG_READ(("writing %i bytes to file as base64 [%i]. Currently %i\n", z, strlen(t), size));
+					pst_fwrite(t, 1, strlen(t), h->fp);
+					free(t);	// caught by valgrind
+				}
 			}
 			else if (h->fp) {
 				DEBUG_READ(("writing %i bytes to file. Currently %i\n", z, size));
--- a/src/libpst.h	Sun Aug 12 14:30:15 2007 -0700
+++ b/src/libpst.h	Mon Aug 20 20:43:17 2007 -0700
@@ -448,6 +448,7 @@
 
 typedef struct _pst_num_array {
   int32_t count_item;
+  int32_t orig_count;
   int32_t count_array;
   struct _pst_num_item ** items;
   struct _pst_num_array *next;
@@ -477,7 +478,7 @@
 pst_item* _pst_getItem(pst_file *pf, pst_desc_ll *d_ptr);
 void * _pst_parse_item (pst_file *pf, pst_desc_ll *d_ptr);
 pst_num_array * _pst_parse_block(pst_file *pf, u_int32_t block_id, pst_index2_ll *i2_head);
-int32_t _pst_process(pst_num_array *list, pst_item *item);
+int32_t _pst_process(pst_num_array *list, pst_item *item, pst_item_attach *attach);
 int32_t _pst_free_list(pst_num_array *list);
 void _pst_freeItem(pst_item *item);
 int32_t _pst_free_id2(pst_index2_ll * head);
--- a/src/readpst.c	Sun Aug 12 14:30:15 2007 -0700
+++ b/src/readpst.c	Mon Aug 20 20:43:17 2007 -0700
@@ -60,9 +60,9 @@
 	int32_t email_count;
 	int32_t skip_count;
 	int32_t type;
-	struct file_ll *next;
 };
 
+void	  process(pst_item *outeritem, pst_desc_ll *d_ptr);
 void	  write_email_body(FILE *f, char *body);
 char*	  removeCR (char *c);
 int32_t   usage();
@@ -71,7 +71,7 @@
 int32_t   close_kmail_dir();
 char*	  mk_recurse_dir(char*);
 int32_t   close_recurse_dir();
-char*	  mk_seperate_dir(char *dir, int overwrite);
+char*	  mk_seperate_dir(char *dir);
 int32_t   close_seperate_dir();
 int32_t   mk_seperate_file(struct file_ll *f);
 char*	  my_stristr(char *haystack, char *needle);
@@ -87,7 +87,8 @@
 void	  write_vcard(FILE* f_output, pst_item_contact* contact, char comment[]);
 void	  write_appointment(FILE* f_output, pst_item_appointment* appointment,
 							pst_item_email* email, FILETIME* create_date, FILETIME* modify_date);
-void	  create_enter_dir(struct file_ll* f, char file_as[], int mode, int overwrite);
+void	  create_enter_dir(struct file_ll* f, pst_item *item);
+void	  close_enter_dir(struct file_ll *f);
 
 char*  prog_name;
 char*  output_dir = ".";
@@ -125,26 +126,142 @@
 // mime type for the attachment
 #define RTF_ATTACH_TYPE "application/rtf"
 
+// global settings
+int mode = MODE_NORMAL;
+int mode_MH = 0;
+int output_mode = OUTPUT_NORMAL;
+int contact_mode = CMODE_VCARD;
+int overwrite = 0;
+int save_rtf_body = 1;
+pst_file pstfile;
+
+
+
+void process(pst_item *outeritem, pst_desc_ll *d_ptr)
+{
+	struct file_ll ff;
+	pst_item *item = NULL;
+
+	DEBUG_ENT("process");
+	memset(&ff, 0, sizeof(ff));
+	create_enter_dir(&ff, outeritem);
+
+	while (d_ptr) {
+		DEBUG_MAIN(("main: New item record\n"));
+		if (!d_ptr->desc) {
+			DEBUG_WARN(("main: ERROR ?? item's desc record is NULL\n"));
+			ff.skip_count++;
+		}
+		else {
+			DEBUG_MAIN(("main: Desc Email ID %#x [d_ptr->id = %#x]\n", d_ptr->desc->id, d_ptr->id));
+
+			item = _pst_parse_item(&pstfile, d_ptr);
+			DEBUG_MAIN(("main: About to process item\n"));
+			if (item && item->email && item->email->subject && item->email->subject->subj) {
+				DEBUG_EMAIL(("item->email->subject = %p\n", item->email->subject));
+				DEBUG_EMAIL(("item->email->subject->subj = %p\n", item->email->subject->subj));
+			}
+			if (item) {
+				if (item->message_store) {
+					// there should only be one message_store, and we have already done it
+					DIE(("main: A second message_store has been found. Sorry, this must be an error.\n"));
+				}
+
+				if (item->folder && d_ptr->child && strcasecmp(item->file_as, "Deleted Items")) {
+					//if this is a non-empty folder other than deleted items, we want to recurse into it
+					if (output_mode != OUTPUT_QUIET) printf("Processing Folder \"%s\"\n", item->file_as);
+					process(item, d_ptr->child);
+
+				} else if (item->contact) {
+					// deal with a contact
+					// write them to the file, one per line in this format
+					// Desc Name <email@address>\n
+					if (mode == MODE_SEPERATE) mk_seperate_file(&ff);
+					ff.email_count++;
+					DEBUG_MAIN(("main: Processing Contact\n"));
+					if (ff.type != PST_TYPE_CONTACT) {
+						DEBUG_MAIN(("main: I have a contact, but the folder isn't a contacts folder. "
+								"Will process anyway\n"));
+					}
+					if (item->type != PST_TYPE_CONTACT) {
+						DEBUG_MAIN(("main: I have an item that has contact info, but doesn't say that"
+								" it is a contact. Type is \"%s\"\n", item->ascii_type));
+						DEBUG_MAIN(("main: Processing anyway\n"));
+					}
+					if (!item->contact) { // this is an incorrect situation. Inform user
+						DEBUG_MAIN(("main: ERROR. This contact has not been fully parsed. one of the pre-requisties is NULL\n"));
+					} else {
+						if (contact_mode == CMODE_VCARD)
+							write_vcard(ff.output, item->contact, item->comment);
+						else
+							fprintf(ff.output, "%s <%s>\n", item->contact->fullname, item->contact->address1);
+					}
+
+				} else if (item->email && (item->type == PST_TYPE_NOTE || item->type == PST_TYPE_REPORT)) {
+					if (mode == MODE_SEPERATE) mk_seperate_file(&ff);
+					ff.email_count++;
+					DEBUG_MAIN(("main: seen an email\n"));
+					write_normal_email(ff.output, ff.name, item, mode, mode_MH, &pstfile, save_rtf_body);
+
+				} else if (item->type == PST_TYPE_JOURNAL) {
+					// deal with journal items
+					if (mode == MODE_SEPERATE) mk_seperate_file(&ff);
+					ff.email_count++;
+
+					DEBUG_MAIN(("main: Processing Journal Entry\n"));
+					if (ff.type != PST_TYPE_JOURNAL) {
+						DEBUG_MAIN(("main: I have a journal entry, but folder isn't specified as a journal type. Processing...\n"));
+					}
+
+					/*	if (item->type != PST_TYPE_JOURNAL) {
+						DEBUG_MAIN(("main: I have an item with journal info, but it's type is \"%s\" \n. Processing...\n",
+						item->ascii_type));
+						}*/
+					fprintf(ff.output, "BEGIN:VJOURNAL\n");
+					if (item->email->subject)
+						fprintf(ff.output, "SUMMARY:%s\n", rfc2426_escape(item->email->subject->subj));
+					if (item->email->body)
+						fprintf(ff.output, "DESCRIPTION:%s\n", rfc2426_escape(item->email->body));
+					if (item->journal->start)
+						fprintf(ff.output, "DTSTART;VALUE=DATE-TIME:%s\n", rfc2445_datetime_format(item->journal->start));
+					fprintf(ff.output, "END:VJOURNAL\n\n");
+
+				} else if (item->type == PST_TYPE_APPOINTMENT) {
+					// deal with Calendar appointments
+					if (mode == MODE_SEPERATE) mk_seperate_file(&ff);
+					ff.email_count++;
+					DEBUG_MAIN(("main: Processing Appointment Entry\n"));
+					if (ff.type != PST_TYPE_APPOINTMENT) {
+						DEBUG_MAIN(("main: I have an appointment, but folder isn't specified as an appointment type. Processing...\n"));
+					}
+					write_appointment(ff.output, item->appointment, item->email, item->create_date, item->modify_date);
+
+				} else {
+					ff.skip_count++;
+					DEBUG_MAIN(("main: Unknown item type. %i. Ascii1=\"%s\"\n",
+							item->type, item->ascii_type));
+				}
+				_pst_freeItem(item);
+			} else {
+				ff.skip_count++;
+				DEBUG_MAIN(("main: A NULL item was seen\n"));
+			}
+			d_ptr = d_ptr->next;
+		}
+	}
+	close_enter_dir(&ff);
+	DEBUG_RET();
+}
+
+
 
 int main(int argc, char** argv) {
 	pst_item *item = NULL;
-	pst_file pstfile;
 	pst_desc_ll *d_ptr;
 	char * fname = NULL;
 	char *d_log=NULL;
 	int c,x;
-	int mode = MODE_NORMAL;
-	int mode_MH = 0;
-	int output_mode = OUTPUT_NORMAL;
-	int contact_mode = CMODE_VCARD;
-	int overwrite = 0;
-	char *enc = NULL;				 // base64 encoded attachment
-	char *boundary = NULL, *b1, *b2; // the boundary marker between multipart sections
 	char *temp = NULL;				 //temporary char pointer
-	char *attach_filename = NULL;
-	int  skip_child = 0;
-	struct file_ll	*f, *head;
-	int save_rtf_body = 1;
 	prog_name = argv[0];
 
 	// command-line option handling
@@ -203,14 +320,6 @@
 		}
 	}
 
-#ifdef DEBUG_ALL
-	// force a log file
-	if (!d_log) d_log = "readpst.log";
-#endif // defined DEBUG_ALL
-	DEBUG_INIT(d_log);
-	DEBUG_REGISTER_CLOSE();
-	DEBUG_ENT("main");
-
 	if (argc > optind) {
 		fname = argv[optind];
 	} else {
@@ -218,26 +327,34 @@
 		exit(2);
 	}
 
+	#ifdef DEBUG_ALL
+		// force a log file
+		if (!d_log) d_log = "readpst.log";
+	#endif // defined DEBUG_ALL
+	DEBUG_INIT(d_log);
+	DEBUG_REGISTER_CLOSE();
+	DEBUG_ENT("main");
+
 	if (output_mode != OUTPUT_QUIET) printf("Opening PST file and indexes...\n");
 
-	DEBUG_MAIN(("main: Opening PST file '%s'\n", fname));
 	RET_DERROR(pst_open(&pstfile, fname, "r"), 1, ("Error opening File\n"));
-	DEBUG_MAIN(("main: Loading Indexes\n"));
 	RET_DERROR(pst_load_index(&pstfile), 2, ("Index Error\n"));
-	DEBUG_MAIN(("processing file items\n"));
 
 	pst_load_extended_attributes(&pstfile);
 
 	if (chdir(output_dir)) {
 		x = errno;
 		pst_close(&pstfile);
+		DEBUG_RET();
 		DIE(("main: Cannot change to output dir %s: %s\n", output_dir, strerror(x)));
 	}
 
 	if (output_mode != OUTPUT_QUIET) printf("About to start processing first record...\n");
 
 	d_ptr = pstfile.d_head; // first record is main record
-	if (!(item = _pst_parse_item(&pstfile, d_ptr)) || !item->message_store) {
+	item  = (pst_item*)_pst_parse_item(&pstfile, d_ptr);
+	if (!item || !item->message_store) {
+		DEBUG_RET();
 		DIE(("main: Could not get root record\n"));
 	}
 
@@ -256,243 +373,17 @@
 	}
 	DEBUG_MAIN(("main: Root Folder Name: %s\n", item->file_as));
 
-
-	f = (struct file_ll*) malloc(sizeof(struct file_ll));
-	memset(f, 0, sizeof(struct file_ll));
-	f->email_count = 0;
-	f->skip_count = 0;
-	f->next = NULL;
-	head = f;
-	create_enter_dir(f, item->file_as, mode, overwrite);
-	f->type = item->type;
-
-	if (!(d_ptr = pst_getTopOfFolders(&pstfile, item))) {
+	d_ptr = pst_getTopOfFolders(&pstfile, item);
+	if (!d_ptr) {
+		DEBUG_RET();
 		DIE(("Top of folders record not found. Cannot continue\n"));
 	}
 
-	if (item){
-		_pst_freeItem(item);
-		item = NULL;
-	}
-
-	d_ptr = d_ptr->child; // do the children of TOPF
-
-	if (output_mode != OUTPUT_QUIET) printf("Processing items...\n");
-
-	DEBUG_MAIN(("main: About to do email stuff\n"));
-	while (d_ptr) {
-		DEBUG_MAIN(("main: New item record\n"));
-		if (!d_ptr->desc) {
-			DEBUG_WARN(("main: ERROR ?? item's desc record is NULL\n"));
-			f->skip_count++;
-			goto check_parent;
-		}
-		DEBUG_MAIN(("main: Desc Email ID %#x [d_ptr->id = %#x]\n", d_ptr->desc->id, d_ptr->id));
-
-		item = _pst_parse_item(&pstfile, d_ptr);
-		DEBUG_MAIN(("main: About to process item\n"));
-		if (item && item->email && item->email->subject && item->email->subject->subj) {
-			DEBUG_EMAIL(("item->email->subject = %p\n", item->email->subject));
-			DEBUG_EMAIL(("item->email->subject->subj = %p\n", item->email->subject->subj));
-		}
-		if (item) {
-			if (item->message_store) {
-				// there should only be one message_store, and we have already done it
-				DIE(("main: A second message_store has been found. Sorry, this must be an error.\n"));
-			}
-
-			if (item->folder) {
-				// if this is a folder, we want to recurse into it
-				if (output_mode != OUTPUT_QUIET) printf("Processing Folder \"%s\"\n", item->file_as);
-				//	f->email_count++;
-				DEBUG_MAIN(("main: I think I may try to go into folder \"%s\"\n", item->file_as));
-				f = (struct file_ll*) malloc(sizeof(struct file_ll));
-				memset(f, 0, sizeof(struct file_ll));
-
-				f->next = head;
-				f->email_count = 0;
-				f->type = item->type;
-				f->stored_count = item->folder->email_count;
-				head = f;
-
-				temp = item->file_as;
-				temp = check_filename(temp);
-				create_enter_dir(f, item->file_as, mode, overwrite);
-				if (d_ptr->child) {
-					d_ptr = d_ptr->child;
-					skip_child = 1;
-				} else {
-					DEBUG_MAIN(("main: Folder has NO children. Creating directory, and closing again\n"));
-					if (output_mode != OUTPUT_QUIET) printf("\tNo items to process in folder \"%s\", should have been %i\n", f->dname, f->stored_count);
-					head = f->next;
-					if (f->output)
-						fclose(f->output);
-					if (mode == MODE_KMAIL)
-						close_kmail_dir();
-					else if (mode == MODE_RECURSE)
-						close_recurse_dir();
-					else if (mode == MODE_SEPERATE)
-						close_seperate_dir();
-					free(f->dname);
-					free(f->name);
-					free(f);
-
-					f = head;
-				}
-				_pst_freeItem(item);
-				item = NULL;
-				goto check_parent;
-			} else if (item->contact) {
-				// deal with a contact
-				// write them to the file, one per line in this format
-				// Desc Name <email@address>\n
-				if (mode == MODE_SEPERATE) {
-					mk_seperate_file(f);
-				}
-				f->email_count++;
-
-				DEBUG_MAIN(("main: Processing Contact\n"));
-				if (f->type != PST_TYPE_CONTACT) {
-					DEBUG_MAIN(("main: I have a contact, but the folder isn't a contacts folder. "
-							"Will process anyway\n"));
-				}
-				if (item->type != PST_TYPE_CONTACT) {
-					DEBUG_MAIN(("main: I have an item that has contact info, but doesn't say that"
-							" it is a contact. Type is \"%s\"\n", item->ascii_type));
-					DEBUG_MAIN(("main: Processing anyway\n"));
-				}
-				if (!item->contact) { // this is an incorrect situation. Inform user
-					DEBUG_MAIN(("main: ERROR. This contact has not been fully parsed. one of the pre-requisties is NULL\n"));
-				} else {
-					if (contact_mode == CMODE_VCARD)
-						write_vcard(f->output, item->contact, item->comment);
-					else
-						fprintf(f->output, "%s <%s>\n", item->contact->fullname, item->contact->address1);
-				}
-			} else if (item->email && (item->type == PST_TYPE_NOTE || item->type == PST_TYPE_REPORT)) {
-				if (mode == MODE_SEPERATE) {
-					mk_seperate_file(f);
-				}
-
-				f->email_count++;
-
-				DEBUG_MAIN(("main: seen an email\n"));
-				write_normal_email(f->output, f->name, item, mode, mode_MH, &pstfile, save_rtf_body);
-			} else if (item->type == PST_TYPE_JOURNAL) {
-				// deal with journal items
-				if (mode == MODE_SEPERATE) {
-					mk_seperate_file(f);
-				}
-				f->email_count++;
-
-				DEBUG_MAIN(("main: Processing Journal Entry\n"));
-				if (f->type != PST_TYPE_JOURNAL) {
-					DEBUG_MAIN(("main: I have a journal entry, but folder isn't specified as a journal type. Processing...\n"));
-				}
-
-				/*	if (item->type != PST_TYPE_JOURNAL) {
-					DEBUG_MAIN(("main: I have an item with journal info, but it's type is \"%s\" \n. Processing...\n",
-					item->ascii_type));
-					}*/
-				fprintf(f->output, "BEGIN:VJOURNAL\n");
-				if (item->email->subject)
-					fprintf(f->output, "SUMMARY:%s\n", rfc2426_escape(item->email->subject->subj));
-				if (item->email->body)
-					fprintf(f->output, "DESCRIPTION:%s\n", rfc2426_escape(item->email->body));
-				if (item->journal->start)
-					fprintf(f->output, "DTSTART;VALUE=DATE-TIME:%s\n", rfc2445_datetime_format(item->journal->start));
-				fprintf(f->output, "END:VJOURNAL\n\n");
-			} else if (item->type == PST_TYPE_APPOINTMENT) {
-				// deal with Calendar appointments
-				if (mode == MODE_SEPERATE) {
-					mk_seperate_file(f);
-				}
-				f->email_count++;
-
-				DEBUG_MAIN(("main: Processing Appointment Entry\n"));
-				if (f->type != PST_TYPE_APPOINTMENT) {
-					DEBUG_MAIN(("main: I have an appointment, but folder isn't specified as an appointment type. Processing...\n"));
-				}
-				write_appointment(f->output, item->appointment, item->email, item->create_date, item->modify_date);
-			} else {
-				f->skip_count++;
-				DEBUG_MAIN(("main: Unknown item type. %i. Ascii1=\"%s\"\n",
-						item->type, item->ascii_type));
-			}
-		} else {
-			f->skip_count++;
-			DEBUG_MAIN(("main: A NULL item was seen\n"));
-		}
-
-		DEBUG_MAIN(("main: Going to next d_ptr\n"));
-
-	check_parent:
-		//	  _pst_freeItem(item);
-		while (!skip_child && !d_ptr->next && d_ptr->parent) {
-			DEBUG_MAIN(("main: Going to Parent\n"));
-			head = f->next;
-			if (f->output) fclose(f->output);
-			DEBUG_MAIN(("main: Email Count for folder %s is %i\n", f->dname, f->email_count));
-			if (output_mode != OUTPUT_QUIET)
-				printf("\t\"%s\" - %i items done, skipped %i, should have been %i\n",
-					   f->dname, f->email_count, f->skip_count, f->stored_count);
-			if (mode == MODE_KMAIL)
-				close_kmail_dir();
-			else if (mode == MODE_RECURSE)
-				close_recurse_dir();
-			else if (mode == MODE_SEPERATE)
-				close_seperate_dir();
-			free(f->name);
-			free(f->dname);
-			free(f);
-			f = head;
-			if (!head) { //we can't go higher. Must be at start?
-				DEBUG_MAIN(("main: We are now trying to go above the highest level. We must be finished\n"));
-				break; //from main while loop
-			}
-			d_ptr = d_ptr->parent;
-			skip_child = 0;
-		}
-
-		if (item) {
-			DEBUG_MAIN(("main: Freeing memory used by item\n"));
-			_pst_freeItem(item);
-			item = NULL;
-		}
-
-		if (!skip_child)
-			d_ptr = d_ptr->next;
-		else
-			skip_child = 0;
-
-		if (!d_ptr) {
-			DEBUG_MAIN(("main: d_ptr is now NULL\n"));
-		}
-	}
-	if (output_mode != OUTPUT_QUIET) printf("Finished.\n");
-	DEBUG_MAIN(("main: Finished.\n"));
-
+	process(item, d_ptr->child);  // do the children of TOPF
+	_pst_freeItem(item);
 	pst_close(&pstfile);
-	//	fclose(pstfile.fp);
-	while (f) {
-		if (f->output) fclose(f->output);
-		free(f->name);
-		free(f->dname);
-
-		if (mode == MODE_KMAIL)
-			close_kmail_dir();
-		else if (mode == MODE_RECURSE)
-			close_recurse_dir();
-		else if (mode == MODE_SEPERATE)
-			// DO SOMETHING HERE
-			;
-		head = f->next;
-		free (f);
-		f = head;
-	}
 
 	DEBUG_RET();
-
 	return 0;
 }
 
@@ -667,7 +558,7 @@
 }
 
 
-char *mk_seperate_dir(char *dir, int overwrite) {
+char *mk_seperate_dir(char *dir) {
 	DEBUG_ENT("mk_seperate_dir");
 	#if !defined(WIN32) && !defined(__CYGWIN__)
 		DIR * sdir = NULL;
@@ -677,9 +568,6 @@
 
 	char *dir_name = NULL;
 	int x = 0, y = 0;
-	/*#if defined(WIN32) || defined(__CYGWIN__)
-	  DIE(("mk_seperate_dir: Win32 applications cannot use this function yet.\n"));
-	  #endif*/
 
 	dir_name = xmalloc(strlen(dir)+10);
 
@@ -726,9 +614,6 @@
 #endif
 	}
 
-	// overwrite will never change during this function, it is just there so that
-	//	if overwrite is set, we only go through this loop once.
-
 	// we don't return a filename here cause it isn't necessary.
 	DEBUG_RET();
 	return NULL;
@@ -755,8 +640,7 @@
 		DIE(("mk_seperate_file: The number of emails in this folder has become too high to handle"));
 	}
 	sprintf(f->name, SEP_MAIL_FILE_TEMPLATE, f->email_count + name_offset);
-	if (f->output)
-		fclose(f->output);
+	if (f->output) fclose(f->output);
 	f->output = NULL;
 	f->name = check_filename(f->name);
 	if (!(f->output = fopen(f->name, "w"))) {
@@ -872,14 +756,11 @@
 
 
 char *rfc2425_datetime_format(FILETIME *ft) {
-	static char * buffer = NULL;
+	static char* buffer = NULL;
 	struct tm *stm = NULL;
 	DEBUG_ENT("rfc2425_datetime_format");
-	if (!buffer)
-		buffer = malloc(30); // should be enough for the date as defined below
-
+	if (!buffer) buffer = malloc(30); // should be enough for the date as defined below
 	stm = fileTimeToStructTM(ft);
-	//Year[4]-Month[2]-Day[2] Hour[2]:Min[2]:Sec[2]
 	if (strftime(buffer, 30, "%Y-%m-%dT%H:%M:%SZ", stm)==0) {
 		DEBUG_INFO(("Problem occured formatting date\n"));
 	}
@@ -892,8 +773,7 @@
 	static char* buffer = NULL;
 	struct tm *stm = NULL;
 	DEBUG_ENT("rfc2445_datetime_format");
-	if (!buffer)
-		buffer = malloc(30); // should be enough
+	if (!buffer) buffer = malloc(30); // should be enough for the date as defined below
 	stm = fileTimeToStructTM(ft);
 	if (strftime(buffer, 30, "%Y%m%dT%H%M%SZ", stm)==0) {
 		DEBUG_INFO(("Problem occured formatting date\n"));
@@ -1277,9 +1157,7 @@
 
 	// attachments
 	attach_num = 0;
-	for (current_attach = item->attach;
-		   current_attach;
-		   current_attach = current_attach->next) {
+	for (current_attach = item->attach; current_attach; current_attach = current_attach->next) {
 		DEBUG_EMAIL(("Attempting Attachment encoding\n"));
 		if (!current_attach->data) {
 			DEBUG_EMAIL(("Data of attachment is NULL!. Size is supposed to be %i\n", current_attach->size));
@@ -1301,16 +1179,22 @@
 
 void write_vcard(FILE* f_output, pst_item_contact* contact, char comment[])
 {
+	// We can only call rfc escape once per printf, since the second call
+	// may free the buffer returned by the first call.
+	// I had tried to place those into a single printf - Carl.
+
 	DEBUG_ENT("write_vcard");
 	// the specification I am following is (hopefully) RFC2426 vCard Mime Directory Profile
 	fprintf(f_output, "BEGIN:VCARD\n");
 	fprintf(f_output, "FN:%s\n", rfc2426_escape(contact->fullname));
-	fprintf(f_output, "N:%s;%s;%s;%s;%s\n",
-		(!contact->surname) 		? "" : rfc2426_escape(contact->surname),
-		(!contact->first_name)			? "" : rfc2426_escape(contact->first_name),
-		(!contact->middle_name) 		? "" : rfc2426_escape(contact->middle_name),
-		(!contact->display_name_prefix) ? "" : rfc2426_escape(contact->display_name_prefix),
-		(!contact->suffix)				? "" : rfc2426_escape(contact->suffix));
+
+	//fprintf(f_output, "N:%s;%s;%s;%s;%s\n",
+	fprintf(f_output, "N:%s;", (!contact->surname)             ? "" : rfc2426_escape(contact->surname));
+	fprintf(f_output, "%s;",   (!contact->first_name)          ? "" : rfc2426_escape(contact->first_name));
+	fprintf(f_output, "%s;",   (!contact->middle_name)         ? "" : rfc2426_escape(contact->middle_name));
+	fprintf(f_output, "%s;",   (!contact->display_name_prefix) ? "" : rfc2426_escape(contact->display_name_prefix));
+	fprintf(f_output, "%s\n",  (!contact->suffix)              ? "" : rfc2426_escape(contact->suffix));
+
 	if (contact->nickname)
 		fprintf(f_output, "NICKNAME:%s\n", rfc2426_escape(contact->nickname));
 	if (contact->address1)
@@ -1321,114 +1205,67 @@
 		fprintf(f_output, "EMAIL:%s\n", rfc2426_escape(contact->address3));
 	if (contact->birthday)
 		fprintf(f_output, "BDAY:%s\n", rfc2425_datetime_format(contact->birthday));
+
 	if (contact->home_address) {
-		fprintf(f_output, "ADR;TYPE=home:%s;%s;%s;%s;%s;%s;%s\n",
-			(!contact->home_po_box) 	 ? "" : rfc2426_escape(contact->home_po_box),
-			   "", // extended Address
-			(!contact->home_street) 	 ? "" : rfc2426_escape(contact->home_street),
-			(!contact->home_city)		 ? "" : rfc2426_escape(contact->home_city),
-			(!contact->home_state)		 ? "" : rfc2426_escape(contact->home_state),
-			(!contact->home_postal_code) ? "" : rfc2426_escape(contact->home_postal_code),
-			(!contact->home_country)	 ? "" : rfc2426_escape(contact->home_country));
+		//fprintf(f_output, "ADR;TYPE=home:%s;%s;%s;%s;%s;%s;%s\n",
+		fprintf(f_output, "ADR;TYPE=home:%s;",  (!contact->home_po_box)      ? "" : rfc2426_escape(contact->home_po_box));
+		fprintf(f_output, "%s;",                ""); // extended Address
+		fprintf(f_output, "%s;",                (!contact->home_street)      ? "" : rfc2426_escape(contact->home_street));
+		fprintf(f_output, "%s;",                (!contact->home_city)        ? "" : rfc2426_escape(contact->home_city));
+		fprintf(f_output, "%s;",                (!contact->home_state)       ? "" : rfc2426_escape(contact->home_state));
+		fprintf(f_output, "%s;",                (!contact->home_postal_code) ? "" : rfc2426_escape(contact->home_postal_code));
+		fprintf(f_output, "%s\n",               (!contact->home_country)     ? "" : rfc2426_escape(contact->home_country));
 		fprintf(f_output, "LABEL;TYPE=home:%s\n", rfc2426_escape(contact->home_address));
 	}
+
 	if (contact->business_address) {
-		// these should be equivalent, but valgrind complains about the single large fprintf
-		//
-		char *ab = (!contact->business_po_box	  ) ? "" : rfc2426_escape(contact->business_po_box     );
-		char *ac = (!contact->business_street	  ) ? "" : rfc2426_escape(contact->business_street     );
-		char *ad = (!contact->business_city   ) ? "" : rfc2426_escape(contact->business_city       );
-		char *ae = (!contact->business_state	  ) ? "" : rfc2426_escape(contact->business_state      );
-		char *af = (!contact->business_postal_code) ? "" : rfc2426_escape(contact->business_postal_code);
-		char *ag = (!contact->business_country	  ) ? "" : rfc2426_escape(contact->business_country    );
-		fprintf(f_output, "ADR;TYPE=work:%s;%s;%s;%s;%s;%s;%s\n", ab, "", ac, ad, ae, af, ag);
-	  //fprintf(f_output, "ADR;TYPE=work:%s;%s;%s;%s;%s;%s;%s\n",
-	  //	(!contact->business_po_box)  ? "" : rfc2426_escape(contact->business_po_box),
-	  //	"", // extended Address
-	  //	(!contact->business_street)  ? "" : rfc2426_escape(contact->business_street),
-	  //	(!contact->business_city)		 ? "" : rfc2426_escape(contact->business_city),
-	  //	(!contact->business_state)		 ? "" : rfc2426_escape(contact->business_state),
-	  //	(!contact->business_postal_code) ? "" : rfc2426_escape(contact->business_postal_code),
-	  //	(!contact->business_country)	 ? "" : rfc2426_escape(contact->business_country));
+		//fprintf(f_output, "ADR;TYPE=work:%s;%s;%s;%s;%s;%s;%s\n",
+		fprintf(f_output, "ADR;TYPE=work:%s;",  (!contact->business_po_box)      ? "" : rfc2426_escape(contact->business_po_box));
+		fprintf(f_output, "%s;",                ""); // extended Address
+		fprintf(f_output, "%s;",                (!contact->business_street)      ? "" : rfc2426_escape(contact->business_street));
+		fprintf(f_output, "%s;",                (!contact->business_city)        ? "" : rfc2426_escape(contact->business_city));
+		fprintf(f_output, "%s;",                (!contact->business_state)       ? "" : rfc2426_escape(contact->business_state));
+		fprintf(f_output, "%s;",                (!contact->business_postal_code) ? "" : rfc2426_escape(contact->business_postal_code));
+		fprintf(f_output, "%s\n",               (!contact->business_country)     ? "" : rfc2426_escape(contact->business_country));
 		fprintf(f_output, "LABEL;TYPE=work:%s\n", rfc2426_escape(contact->business_address));
 	}
+
 	if (contact->other_address) {
-		fprintf(f_output, "ADR;TYPE=postal:%s;%s;%s;%s;%s;%s;%s\n",
-			(!contact->other_po_box)	   ? "" : rfc2426_escape(contact->other_po_box),
-			"", // extended Address
-			(!contact->other_street)	   ? "" : rfc2426_escape(contact->other_street),
-			(!contact->other_city)		   ? "" : rfc2426_escape(contact->other_city),
-			(!contact->other_state) 	   ? "" : rfc2426_escape(contact->other_state),
-			(!contact->other_postal_code)  ? "" : rfc2426_escape(contact->other_postal_code),
-			(!contact->other_country)	   ? "" : rfc2426_escape(contact->other_country));
+		//fprintf(f_output, "ADR;TYPE=postal:%s;%s;%s;%s;%s;%s;%s\n",
+		fprintf(f_output, "ADR;TYPE=postal:%s;",(!contact->other_po_box)       ? "" : rfc2426_escape(contact->other_po_box));
+		fprintf(f_output, "%s;",                ""); // extended Address
+		fprintf(f_output, "%s;",                (!contact->other_street)       ? "" : rfc2426_escape(contact->other_street));
+		fprintf(f_output, "%s;",                (!contact->other_city)         ? "" : rfc2426_escape(contact->other_city));
+		fprintf(f_output, "%s;",                (!contact->other_state)        ? "" : rfc2426_escape(contact->other_state));
+		fprintf(f_output, "%s;",                (!contact->other_postal_code)  ? "" : rfc2426_escape(contact->other_postal_code));
+		fprintf(f_output, "%s\n",               (!contact->other_country)      ? "" : rfc2426_escape(contact->other_country));
 		fprintf(f_output, "LABEL;TYPE=postal:%s\n", rfc2426_escape(contact->other_address));
 	}
-	if (contact->business_fax)
-		fprintf(f_output, "TEL;TYPE=work,fax:%s\n",
-			rfc2426_escape(contact->business_fax));
-	if (contact->business_phone)
-		fprintf(f_output, "TEL;TYPE=work,voice:%s\n",
-			rfc2426_escape(contact->business_phone));
-	if (contact->business_phone2)
-		fprintf(f_output, "TEL;TYPE=work,voice:%s\n",
-			rfc2426_escape(contact->business_phone2));
-	if (contact->car_phone)
-		fprintf(f_output, "TEL;TYPE=car,voice:%s\n",
-			rfc2426_escape(contact->car_phone));
-	if (contact->home_fax)
-		fprintf(f_output, "TEL;TYPE=home,fax:%s\n",
-			rfc2426_escape(contact->home_fax));
-	if (contact->home_phone)
-		fprintf(f_output, "TEL;TYPE=home,voice:%s\n",
-			rfc2426_escape(contact->home_phone));
-	if (contact->home_phone2)
-		fprintf(f_output, "TEL;TYPE=home,voice:%s\n",
-			rfc2426_escape(contact->home_phone2));
-	if (contact->isdn_phone)
-		fprintf(f_output, "TEL;TYPE=isdn:%s\n",
-			rfc2426_escape(contact->isdn_phone));
-	if (contact->mobile_phone)
-		fprintf(f_output, "TEL;TYPE=cell,voice:%s\n",
-			rfc2426_escape(contact->mobile_phone));
-	if (contact->other_phone)
-		fprintf(f_output, "TEL;TYPE=msg:%s\n",
-			rfc2426_escape(contact->other_phone));
-	if (contact->pager_phone)
-		fprintf(f_output, "TEL;TYPE=pager:%s\n",
-			rfc2426_escape(contact->pager_phone));
-	if (contact->primary_fax)
-		fprintf(f_output, "TEL;TYPE=fax,pref:%s\n",
-			rfc2426_escape(contact->primary_fax));
-	if (contact->primary_phone)
-		fprintf(f_output, "TEL;TYPE=phone,pref:%s\n",
-			rfc2426_escape(contact->primary_phone));
-	if (contact->radio_phone)
-		fprintf(f_output, "TEL;TYPE=pcs:%s\n",
-			rfc2426_escape(contact->radio_phone));
-	if (contact->telex)
-		fprintf(f_output, "TEL;TYPE=bbs:%s\n",
-			rfc2426_escape(contact->telex));
-	if (contact->job_title)
-		fprintf(f_output, "TITLE:%s\n",
-			rfc2426_escape(contact->job_title));
-	if (contact->profession)
-		fprintf(f_output, "ROLE:%s\n",
-			rfc2426_escape(contact->profession));
-	if (contact->assistant_name
-		|| contact->assistant_phone) {
+
+	if (contact->business_fax)		fprintf(f_output, "TEL;TYPE=work,fax:%s\n",         rfc2426_escape(contact->business_fax));
+	if (contact->business_phone)	fprintf(f_output, "TEL;TYPE=work,voice:%s\n",       rfc2426_escape(contact->business_phone));
+	if (contact->business_phone2)	fprintf(f_output, "TEL;TYPE=work,voice:%s\n",       rfc2426_escape(contact->business_phone2));
+	if (contact->car_phone) 		fprintf(f_output, "TEL;TYPE=car,voice:%s\n",        rfc2426_escape(contact->car_phone));
+	if (contact->home_fax)			fprintf(f_output, "TEL;TYPE=home,fax:%s\n",         rfc2426_escape(contact->home_fax));
+	if (contact->home_phone)		fprintf(f_output, "TEL;TYPE=home,voice:%s\n",       rfc2426_escape(contact->home_phone));
+	if (contact->home_phone2)		fprintf(f_output, "TEL;TYPE=home,voice:%s\n",       rfc2426_escape(contact->home_phone2));
+	if (contact->isdn_phone)		fprintf(f_output, "TEL;TYPE=isdn:%s\n",             rfc2426_escape(contact->isdn_phone));
+	if (contact->mobile_phone)		fprintf(f_output, "TEL;TYPE=cell,voice:%s\n",       rfc2426_escape(contact->mobile_phone));
+	if (contact->other_phone)		fprintf(f_output, "TEL;TYPE=msg:%s\n",              rfc2426_escape(contact->other_phone));
+	if (contact->pager_phone)		fprintf(f_output, "TEL;TYPE=pager:%s\n",            rfc2426_escape(contact->pager_phone));
+	if (contact->primary_fax)		fprintf(f_output, "TEL;TYPE=fax,pref:%s\n",         rfc2426_escape(contact->primary_fax));
+	if (contact->primary_phone) 	fprintf(f_output, "TEL;TYPE=phone,pref:%s\n",       rfc2426_escape(contact->primary_phone));
+	if (contact->radio_phone)		fprintf(f_output, "TEL;TYPE=pcs:%s\n",              rfc2426_escape(contact->radio_phone));
+	if (contact->telex) 			fprintf(f_output, "TEL;TYPE=bbs:%s\n",              rfc2426_escape(contact->telex));
+	if (contact->job_title) 		fprintf(f_output, "TITLE:%s\n",                     rfc2426_escape(contact->job_title));
+	if (contact->profession)		fprintf(f_output, "ROLE:%s\n",                      rfc2426_escape(contact->profession));
+	if (contact->assistant_name || contact->assistant_phone) {
 		fprintf(f_output, "AGENT:BEGIN:VCARD\n");
-		if (contact->assistant_name)
-			fprintf(f_output, "FN:%s\n",
-				rfc2426_escape(contact->assistant_name));
-		if (contact->assistant_phone)
-			fprintf(f_output, "TEL:%s\n",
-				rfc2426_escape(contact->assistant_phone));
+		if (contact->assistant_name)	fprintf(f_output, "FN:%s\n",                    rfc2426_escape(contact->assistant_name));
+		if (contact->assistant_phone)	fprintf(f_output, "TEL:%s\n",                   rfc2426_escape(contact->assistant_phone));
 	}
-	if (contact->company_name)
-		fprintf(f_output, "ORG:%s\n",
-			rfc2426_escape(contact->company_name));
-	if (comment)
-		fprintf(f_output, "NOTE:%s\n", rfc2426_escape(comment));
+	if (contact->company_name)		fprintf(f_output, "ORG:%s\n",                       rfc2426_escape(contact->company_name));
+	if (comment)					fprintf(f_output, "NOTE:%s\n",                      rfc2426_escape(comment));
 
 	fprintf(f_output, "VERSION: 3.0\n");
 	fprintf(f_output, "END:VCARD\n\n");
@@ -1514,26 +1351,31 @@
 }
 
 
-void create_enter_dir(struct file_ll* f, char file_as[], int mode, int overwrite)
+void create_enter_dir(struct file_ll* f, pst_item *item)
 {
+	f->email_count = 0;
+	f->skip_count = 0;
+	f->type = item->type;
+	f->stored_count = (item->folder) ? item->folder->email_count : 0;
+
 	DEBUG_ENT("create_enter_dir");
 	if (mode == MODE_KMAIL)
-		f->name = mk_kmail_dir(file_as); //create directory and form filename
+		f->name = mk_kmail_dir(item->file_as); //create directory and form filename
 	else if (mode == MODE_RECURSE)
-		f->name = mk_recurse_dir(file_as);
+		f->name = mk_recurse_dir(item->file_as);
 	else if (mode == MODE_SEPERATE) {
 		// do similar stuff to recurse here.
-		mk_seperate_dir(file_as, overwrite);
+		mk_seperate_dir(item->file_as);
 		f->name = (char*) xmalloc(10);
 		memset(f->name, 0, 10);
 		//		sprintf(f->name, SEP_MAIL_FILE_TEMPLATE, f->email_count);
 	} else {
-		f->name = (char*) xmalloc(strlen(file_as)+strlen(OUTPUT_TEMPLATE)+1);
-		sprintf(f->name, OUTPUT_TEMPLATE, file_as);
+		f->name = (char*) xmalloc(strlen(item->file_as)+strlen(OUTPUT_TEMPLATE)+1);
+		sprintf(f->name, OUTPUT_TEMPLATE, item->file_as);
 	}
 
-	f->dname = (char*) xmalloc(strlen(file_as)+1);
-	strcpy(f->dname, file_as);
+	f->dname = (char*) xmalloc(strlen(item->file_as)+1);
+	strcpy(f->dname, item->file_as);
 
 	if (overwrite != 1) {
 		int x = 0;
@@ -1560,7 +1402,7 @@
 		}
 	}
 
-	DEBUG_MAIN(("f->name = %s\nitem->folder_name = %s\n", f->name, file_as));
+	DEBUG_MAIN(("f->name = %s\nitem->folder_name = %s\n", f->name, item->file_as));
 	if (mode != MODE_SEPERATE) {
 		f->name = check_filename(f->name);
 		if (!(f->output = fopen(f->name, "w"))) {
@@ -1570,3 +1412,22 @@
 	DEBUG_RET();
 }
 
+
+void close_enter_dir(struct file_ll *f)
+{
+	DEBUG_MAIN(("main: Email Count for folder %s is %i\n", f->dname, f->email_count));
+	if (output_mode != OUTPUT_QUIET)
+		printf("\t\"%s\" - %i items done, skipped %i, should have been %i\n",
+			   f->dname, f->email_count, f->skip_count, f->stored_count);
+	if (f->output) fclose(f->output);
+	free(f->name);
+	free(f->dname);
+
+	if (mode == MODE_KMAIL)
+		close_kmail_dir();
+	else if (mode == MODE_RECURSE)
+		close_recurse_dir();
+	else if (mode == MODE_SEPERATE)
+		close_seperate_dir();
+}
+