changeset 151:cda7c812ec01

track character set individually for each mapi element
author Carl Byington <carl@five-ten-sg.com>
date Sun, 08 Mar 2009 14:35:26 -0700
parents 06aa84023b48
children edebaf0e87d2
files ChangeLog regression/regression-tests.bash src/libpst.c src/libpst.h src/libstrfunc.c src/lspst.c src/pst2dii.cpp.in src/pst2ldif.cpp src/readpst.c src/vbuf.c src/vbuf.h
diffstat 11 files changed, 1177 insertions(+), 1639 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu Mar 05 08:23:32 2009 -0800
+++ b/ChangeLog	Sun Mar 08 14:35:26 2009 -0700
@@ -4,6 +4,9 @@
     * remove decrypt option from getidblock - we always decrypt.
     * rename some structure fields to reflect our better understanding
       of the pst format.
+    * track character set for each mapi element, since some could be
+      unicode (therefore utf8) and others sbcs with character set
+      specified by the mapi object.
 
 LibPST 0.6.29 (2009-02-24)
 ===============================
--- a/regression/regression-tests.bash	Thu Mar 05 08:23:32 2009 -0800
+++ b/regression/regression-tests.bash	Sun Mar 08 14:35:26 2009 -0700
@@ -77,8 +77,8 @@
     #doldif  13 test-text.pst
     #doldif  14 joe.romanowski.pst
     #doldif  15 hourig1.pst
-    #doldif  16 hourig2.pst
-    #doldif  17 hourig3.pst
+    ##doldif  16 hourig2.pst
+    ##doldif  17 hourig3.pst
     #doldif  18 test-mac.pst
     doldif  19 harris.pst
 else
@@ -100,7 +100,7 @@
     #dopst  16 hourig2.pst
     #dopst  17 hourig3.pst
     dopst  18 test-mac.pst
-    dopst  19 harris.pst
+    #dopst  19 harris.pst
 fi
 
 grep 'lost:' *err | grep -v 'lost: 0 '
--- a/src/libpst.c	Thu Mar 05 08:23:32 2009 -0800
+++ b/src/libpst.c	Sun Mar 08 14:35:26 2009 -0700
@@ -1115,7 +1115,7 @@
 
     if ((id2_ptr = pst_getID2(id2_head, (uint64_t)0x692))) {
         // DSN/MDN reports?
-        DEBUG_EMAIL(("DSN/MDN processing \n"));
+        DEBUG_EMAIL(("DSN/MDN processing\n"));
         list = pst_parse_block(pf, id2_ptr->id->id, id2_head, NULL);
         if (!list) {
             DEBUG_WARN(("ERROR error processing main DSN/MDN record\n"));
@@ -1141,14 +1141,6 @@
     }
 
     if ((id2_ptr = pst_getID2(id2_head, (uint64_t)0x671))) {
-        // should not have any existing attachments anyway
-        //while (item->attach) {
-        //    DEBUG_EMAIL(("throw away existing attachment\n"));
-        //    attach = item->attach->next;
-        //    free(item->attach);
-        //    item->attach = attach;
-        //}
-
         DEBUG_EMAIL(("ATTACHMENT processing attachment\n"));
         list = pst_parse_block(pf, id2_ptr->id->id, id2_head, NULL);
         if (!list) {
@@ -1718,7 +1710,7 @@
 
 // This version of free does NULL check first
 #define SAFE_FREE(x) {if (x) free(x);}
-
+#define SAFE_FREE_STR(x) SAFE_FREE(x.str)
 
 // check if item->email is NULL, and init if so
 #define MALLOC_EMAIL(x)        { if (!x->email)         { x->email         = (pst_item_email*)         xmalloc(sizeof(pst_item_email));         memset(x->email,         0, sizeof(pst_item_email)        );} }
@@ -1727,19 +1719,70 @@
 #define MALLOC_MESSAGESTORE(x) { if (!x->message_store) { x->message_store = (pst_item_message_store*) xmalloc(sizeof(pst_item_message_store)); memset(x->message_store, 0, sizeof(pst_item_message_store));} }
 #define MALLOC_JOURNAL(x)      { if (!x->journal)       { x->journal       = (pst_item_journal*)       xmalloc(sizeof(pst_item_journal));       memset(x->journal,       0, sizeof(pst_item_journal)      );} }
 #define MALLOC_APPOINTMENT(x)  { if (!x->appointment)   { x->appointment   = (pst_item_appointment*)   xmalloc(sizeof(pst_item_appointment));   memset(x->appointment,   0, sizeof(pst_item_appointment)  );} }
+
 // malloc space and copy the current item's data null terminated
-#define LIST_COPY(targ, type) {                               \
-    targ = type realloc(targ, list->items[x]->size+1);        \
-    memcpy(targ, list->items[x]->data, list->items[x]->size); \
-    memset(((char*)targ)+list->items[x]->size, 0, (size_t)1); \
+#define LIST_COPY(targ, type) {                                 \
+    targ = type realloc(targ, list->items[x]->size+1);          \
+    memcpy(targ, list->items[x]->data, list->items[x]->size);   \
+    memset(((char*)targ)+list->items[x]->size, 0, (size_t)1);   \
+}
+
+#define LIST_COPY_BOOL(label, targ) {                           \
+    if (*(int16_t*)list->items[x]->data) {                      \
+        DEBUG_EMAIL((label" - True\n"));                        \
+        targ = 1;                                               \
+    } else {                                                    \
+        DEBUG_EMAIL((label" - False\n"));                       \
+        targ = 0;                                               \
+    }                                                           \
+}
+
+#define LIST_COPY_EMAIL_BOOL(label, targ) {                     \
+    MALLOC_EMAIL(item);                                         \
+    LIST_COPY_BOOL(label, targ)                                 \
+}
+
+#define LIST_COPY_CONTACT_BOOL(label, targ) {                   \
+    MALLOC_CONTACT(item);                                       \
+    LIST_COPY_BOOL(label, targ)                                 \
 }
+
+#define LIST_COPY_APPT_BOOL(label, targ) {                      \
+    MALLOC_APPOINTMENT(item);                                   \
+    LIST_COPY_BOOL(label, targ)                                 \
+}
+
+// malloc space and copy the current item's data null terminated
+// including the utf8 flag
+#define LIST_COPY_STR(label, targ) {                                    \
+    LIST_COPY(targ.str, (char*));                                       \
+    targ.is_utf8 = (list->items[x]->type == 0x1f) ? 1 : 0;              \
+    DEBUG_EMAIL((label" - unicode %d - %s\n", targ.is_utf8, targ.str)); \
+}
+
+#define LIST_COPY_EMAIL_STR(label, targ) {                      \
+    MALLOC_EMAIL(item);                                         \
+    LIST_COPY_STR(label, targ);                                 \
+}
+
+#define LIST_COPY_CONTACT_STR(label, targ) {                    \
+    MALLOC_CONTACT(item);                                       \
+    LIST_COPY_STR(label, targ);                                 \
+}
+
+#define LIST_COPY_APPT_STR(label, targ) {                       \
+    MALLOC_APPOINTMENT(item);                                   \
+    LIST_COPY_STR(label, targ);                                 \
+}
+
 // malloc space and copy the item filetime
-#define LIST_COPY_TIME(targ) {                                \
-    targ = (FILETIME*) realloc(targ, sizeof(FILETIME));       \
-    memcpy(targ, list->items[x]->data, list->items[x]->size); \
-    LE32_CPU(targ->dwLowDateTime);                            \
-    LE32_CPU(targ->dwHighDateTime);                           \
+#define LIST_COPY_TIME(targ) {                                  \
+    targ = (FILETIME*) realloc(targ, sizeof(FILETIME));         \
+    memcpy(targ, list->items[x]->data, list->items[x]->size);   \
+    LE32_CPU(targ->dwLowDateTime);                              \
+    LE32_CPU(targ->dwHighDateTime);                             \
 }
+
 // malloc space and copy the current item's data and size
 #define LIST_COPY_SIZE(targ, type, mysize) {        \
     mysize = list->items[x]->size;                  \
@@ -1779,8 +1822,8 @@
     }
 
     while (list) {
-        int32_t x = 0;
-        while (x < list->count_item) {
+        int32_t x;
+        for (x=0; x<list->count_item; x++) {
             int32_t t;
             pst_item_extra_field *ef;
             // check here to see if the id is one that is mapped.
@@ -1788,7 +1831,6 @@
 
             switch (list->items[x]->id) {
                 case PST_ATTRIB_HEADER: // CUSTOM attribute for saying the Extra Headers
-                    DEBUG_EMAIL(("Extra Field - "));
                     if (list->items[x]->extra) {
                         ef = (pst_item_extra_field*) xmalloc(sizeof(pst_item_extra_field));
                         memset(ef, 0, sizeof(pst_item_extra_field));
@@ -1797,7 +1839,7 @@
                         LIST_COPY(ef->value, (char*));
                         ef->next = item->extra_fields;
                         item->extra_fields = ef;
-                        DEBUG_EMAIL(("\"%s\" = \"%s\"\n", ef->field_name, ef->value));
+                        DEBUG_EMAIL(("Extra Field - \"%s\" = \"%s\"\n", ef->field_name, ef->value));
                         if (strcmp(ef->field_name, "content-type") == 0) {
                             char *p = strstr(ef->value, "charset=\"");
                             if (p) {
@@ -1807,8 +1849,9 @@
                                     *pp = '\0';
                                     char *set = strdup(p);
                                     *pp = '"';
-                                    if (item->body_charset) free(item->body_charset);
-                                    item->body_charset = set;
+                                    if (item->body_charset.str) free(item->body_charset.str);
+                                    item->body_charset.str     = set;
+                                    item->body_charset.is_utf8 = 1;
                                     DEBUG_EMAIL(("body charset %s from content-type extra field\n", set));
                                 }
                             }
@@ -1820,15 +1863,8 @@
                     break;
                 case 0x0002: // PR_ALTERNATE_RECIPIENT_ALLOWED
                     // If set to true, the sender allows this email to be autoforwarded
-                    DEBUG_EMAIL(("AutoForward allowed - "));
-                    MALLOC_EMAIL(item);
-                    if (*(int16_t*)list->items[x]->data) {
-                        DEBUG_EMAIL(("True\n"));
-                        item->email->autoforward = 1;
-                    } else {
-                        DEBUG_EMAIL(("False\n"));
-                        item->email->autoforward = -1;
-                    }
+                    LIST_COPY_EMAIL_BOOL("AutoForward allowed", item->email->autoforward);
+                    if (!item->email->autoforward) item->email->autoforward = -1;
                     break;
                 case 0x0003: // Extended Attributes table
                     DEBUG_EMAIL(("Extended Attributes Table - NOT PROCESSED\n"));
@@ -1838,18 +1874,16 @@
                     // 0 - Low
                     // 1 - Normal
                     // 2 - High
-                    DEBUG_EMAIL(("Importance Level - "));
                     MALLOC_EMAIL(item);
                     memcpy(&(item->email->importance), list->items[x]->data, sizeof(item->email->importance));
                     LE32_CPU(item->email->importance);
                     t = item->email->importance;
-                    DEBUG_EMAIL(("%s [%i]\n", ((int)t==0?"Low":
-                                              ((int)t==1?"Normal":
-                                                         "High")), t));
+                    DEBUG_EMAIL(("Importance Level - %s [%i]\n", ((int)t==0?"Low"    :
+                                                                 ((int)t==1?"Normal" :
+                                                                            "High")), t));
                     break;
                 case 0x001A: // PR_MESSAGE_CLASS Ascii type of messages - NOT FOLDERS
                     // must be case insensitive
-                    DEBUG_EMAIL(("IPM.x - "));
                     LIST_COPY(item->ascii_type, (char*));
                     if (pst_strincmp("IPM.Note", item->ascii_type, 8) == 0)
                         // the string begins with IPM.Note...
@@ -1872,52 +1906,28 @@
                     else
                         item->type = PST_TYPE_OTHER;
 
-                    DEBUG_EMAIL(("%s\n", item->ascii_type));
+                    DEBUG_EMAIL(("IPM.x - %s\n", item->ascii_type));
                     break;
                 case 0x0023: // PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED
                     // set if the sender wants a delivery report from all recipients
-                    DEBUG_EMAIL(("Global Delivery Report - "));
-                    MALLOC_EMAIL(item);
-                    if (*(int16_t*)list->items[x]->data) {
-                        DEBUG_EMAIL(("True\n"));
-                        item->email->delivery_report = 1;
-                    } else {
-                        DEBUG_EMAIL(("False\n"));
-                        item->email->delivery_report = 0;
-                    }
+                    LIST_COPY_EMAIL_BOOL("Global Delivery Report", item->email->delivery_report);
                     break;
                 case 0x0026: // PR_PRIORITY
                     // Priority of a message
                     // -1 NonUrgent
                     //  0 Normal
                     //  1 Urgent
-                    DEBUG_EMAIL(("Priority - "));
                     MALLOC_EMAIL(item);
                     memcpy(&(item->email->priority), list->items[x]->data, sizeof(item->email->priority));
                     LE32_CPU(item->email->priority);
                     t = item->email->priority;
-                    DEBUG_EMAIL(("%s [%i]\n", (t<0?"NonUrgent":(t==0?"Normal":"Urgent")), t));
+                    DEBUG_EMAIL(("Priority - %s [%i]\n", (t<0?"NonUrgent":(t==0?"Normal":"Urgent")), t));
                     break;
                 case 0x0029: // PR_READ_RECEIPT_REQUESTED
-                    DEBUG_EMAIL(("Read Receipt - "));
-                    MALLOC_EMAIL(item);
-                    if (*(int16_t*)list->items[x]->data) {
-                        DEBUG_EMAIL(("True\n"));
-                        item->email->read_receipt = 1;
-                    } else {
-                        DEBUG_EMAIL(("False\n"));
-                        item->email->read_receipt = 0;
-                    }
+                    LIST_COPY_EMAIL_BOOL("Read Receipt", item->email->read_receipt);
                     break;
                 case 0x002B: // PR_RECIPIENT_REASSIGNMENT_PROHIBITED
-                    DEBUG_EMAIL(("Reassignment Prohibited (Private) - "));
-                    if (*(int16_t*)list->items[x]->data) {
-                        DEBUG_EMAIL(("True\n"));
-                        item->private_member = 1;
-                    } else {
-                        DEBUG_EMAIL(("False\n"));
-                        item->private_member = 0;
-                    }
+                    LIST_COPY_BOOL("Reassignment Prohibited (Private)", item->private_member);
                     break;
                 case 0x002E: // PR_ORIGINAL_SENSITIVITY
                     // the sensitivity of the message before being replied to or forwarded
@@ -1925,21 +1935,19 @@
                     // 1 - Personal
                     // 2 - Private
                     // 3 - Company Confidential
-                    DEBUG_EMAIL(("Original Sensitivity - "));
                     MALLOC_EMAIL(item);
                     memcpy(&(item->email->orig_sensitivity), list->items[x]->data, sizeof(item->email->orig_sensitivity));
                     LE32_CPU(item->email->orig_sensitivity);
                     t = item->email->orig_sensitivity;
-                    DEBUG_EMAIL(("%s [%i]\n", ((int)t==0?"None":
-                                              ((int)t==1?"Personal":
-                                              ((int)t==2?"Private":
-                                                         "Company Confidential"))), t));
+                    DEBUG_EMAIL(("Original Sensitivity - %s [%i]\n", ((int)t==0?"None"     :
+                                                                     ((int)t==1?"Personal" :
+                                                                     ((int)t==2?"Private"  :
+                                                                                "Company Confidential"))), t));
                     break;
                 case 0x0032: // PR_REPORT_TIME
-                    DEBUG_EMAIL(("Report time - "));
                     MALLOC_EMAIL(item);
                     LIST_COPY_TIME(item->email->report_time);
-                    DEBUG_EMAIL(("%s", fileTimeToAscii(item->email->report_time)));
+                    DEBUG_EMAIL(("Report time - %s\n", fileTimeToAscii(item->email->report_time)));
                     break;
                 case 0x0036: // PR_SENSITIVITY
                     // sender's opinion of the sensitivity of an email
@@ -1947,59 +1955,35 @@
                     // 1 - Personal
                     // 2 - Private
                     // 3 - Company Confidential
-                    DEBUG_EMAIL(("Sensitivity - "));
                     MALLOC_EMAIL(item);
                     memcpy(&(item->email->sensitivity), list->items[x]->data, sizeof(item->email->sensitivity));
                     LE32_CPU(item->email->sensitivity);
                     t = item->email->sensitivity;
-                    DEBUG_EMAIL(("%s [%i]\n", ((int)t==0?"None":
-                                              ((int)t==1?"Personal":
-                                              ((int)t==2?"Private":
-                                                         "Company Confidential"))), t));
+                    DEBUG_EMAIL(("Sensitivity - %s [%i]\n", ((int)t==0?"None"     :
+                                                            ((int)t==1?"Personal" :
+                                                            ((int)t==2?"Private"  :
+                                                                       "Company Confidential"))), t));
                     break;
                 case 0x0037: // PR_SUBJECT raw subject
-                    DEBUG_EMAIL(("Raw Subject - "));
-                    MALLOC_EMAIL(item);
-                    item->email->subject = (pst_item_email_subject*) realloc(item->email->subject, sizeof(pst_item_email_subject));
-                    memset(item->email->subject, 0, sizeof(pst_item_email_subject));
-                    DEBUG_EMAIL((" [size = %i] ", list->items[x]->size));
-                    if (list->items[x]->size > 0) {
-                        if (isprint(list->items[x]->data[0]) || (list->items[x]->size < 2)) {
-                            // then there are no control bytes at the front
-                            item->email->subject->off1 = 0;
-                            item->email->subject->off2 = 0;
-                            item->email->subject->subj = realloc(item->email->subject->subj, list->items[x]->size+1);
-                            memset(item->email->subject->subj, 0, list->items[x]->size+1);
-                            memcpy(item->email->subject->subj, list->items[x]->data, list->items[x]->size);
-                        } else {
-                            DEBUG_EMAIL(("Raw Subject has control codes\n"));
-                            // there might be some control bytes in the first and second bytes
-                            item->email->subject->off1 = (int)(unsigned)list->items[x]->data[0];
-                            item->email->subject->off2 = (int)(unsigned)list->items[x]->data[1];
-                            item->email->subject->subj = realloc(item->email->subject->subj, list->items[x]->size-1);
-                            memset(item->email->subject->subj, 0, list->items[x]->size-1);
-                            memcpy(item->email->subject->subj, &(list->items[x]->data[2]), list->items[x]->size-2);
+                    {
+                        int off = 0;
+                        if ((list->items[x]->size > 2) && (((uint8_t)list->items[x]->data[0]) < 0x20)) {
+                            off = 2;
                         }
-                        DEBUG_EMAIL(("%s\n", item->email->subject->subj));
-                    } else {
-                        // obviously outlook has decided not to be straight with this one.
-                        item->email->subject->off1 = 0;
-                        item->email->subject->off2 = 0;
-                        item->email->subject = NULL;
-                        DEBUG_EMAIL(("NULL subject detected\n"));
+                        list->items[x]->data += off;
+                        list->items[x]->size -= off;
+                        LIST_COPY_STR("Raw Subject", item->subject);
+                        list->items[x]->size += off;
+                        list->items[x]->data -= off;
                     }
                     break;
                 case 0x0039: // PR_CLIENT_SUBMIT_TIME Date Email Sent/Created
-                    DEBUG_EMAIL(("Date sent - "));
                     MALLOC_EMAIL(item);
                     LIST_COPY_TIME(item->email->sent_date);
-                    DEBUG_EMAIL(("%s", fileTimeToAscii(item->email->sent_date)));
+                    DEBUG_EMAIL(("Date sent - %s\n", fileTimeToAscii(item->email->sent_date)));
                     break;
                 case 0x003B: // PR_SENT_REPRESENTING_SEARCH_KEY Sender address 1
-                    DEBUG_EMAIL(("Sent on behalf of address 1 - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->outlook_sender, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->outlook_sender));
+                    LIST_COPY_EMAIL_STR("Sent on behalf of address 1", item->email->outlook_sender);
                     break;
                 case 0x003F: // PR_RECEIVED_BY_ENTRYID Structure containing Recipient
                     DEBUG_EMAIL(("Recipient Structure 1 -- NOT HANDLED\n"));
@@ -2010,105 +1994,50 @@
                 case 0x0041: // PR_SENT_REPRESENTING_ENTRYID Structure containing Sender
                     DEBUG_EMAIL(("Sent on behalf of Structure 1 -- NOT HANDLED\n"));
                     break;
-                case 0x0042: // PR_SENT_REPRESENTING_NAME Name of Sender Structure
-                    DEBUG_EMAIL(("Sent on behalf of Structure Name - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->outlook_sender_name, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->outlook_sender_name));
+                case 0x0042: // PR_SENT_REPRESENTING_NAME
+                    LIST_COPY_EMAIL_STR("Sent on behalf of", item->email->outlook_sender_name);
                     break;
                 case 0x0043: // PR_RCVD_REPRESENTING_ENTRYID Recipient Structure 2
                     DEBUG_EMAIL(("Received on behalf of Structure -- NOT HANDLED\n"));
                     break;
-                case 0x0044: // PR_RCVD_REPRESENTING_NAME Name of Recipient Structure 2
-                    DEBUG_EMAIL(("Received on behalf of Structure Name -- NOT HANDLED\n"));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->outlook_recipient_name, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->outlook_recipient_name));
+                case 0x0044: // PR_RCVD_REPRESENTING_NAME
+                    LIST_COPY_EMAIL_STR("Received on behalf of", item->email->outlook_recipient_name);
                     break;
                 case 0x004F: // PR_REPLY_RECIPIENT_ENTRIES Reply-To Structure
                     DEBUG_EMAIL(("Reply-To Structure -- NOT HANDLED\n"));
                     break;
                 case 0x0050: // PR_REPLY_RECIPIENT_NAMES Name of Reply-To Structure
-                    DEBUG_EMAIL(("Name of Reply-To Structure -"));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->reply_to, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->reply_to));
+                    LIST_COPY_EMAIL_STR("Reply-To", item->email->reply_to);
                     break;
                 case 0x0051: // PR_RECEIVED_BY_SEARCH_KEY Recipient Address 1
-                    DEBUG_EMAIL(("Recipient's Address 1 (Search Key) - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY (item->email->outlook_recipient, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->outlook_recipient));
+                    LIST_COPY_EMAIL_STR("Recipient's Address 1", item->email->outlook_recipient);
                     break;
                 case 0x0052: // PR_RCVD_REPRESENTING_SEARCH_KEY Recipient Address 2
-                    DEBUG_EMAIL(("Received on behalf of Address (Search Key) - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->outlook_recipient2, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->outlook_recipient2));
+                    LIST_COPY_EMAIL_STR("Recipient's Address 2", item->email->outlook_recipient2);
                     break;
                 case 0x0057: // PR_MESSAGE_TO_ME
                     // this user is listed explicitly in the TO address
-                    DEBUG_EMAIL(("My address in TO field - "));
-                    MALLOC_EMAIL(item);
-                    if (*(int16_t*)list->items[x]->data) {
-                        DEBUG_EMAIL(("True\n"));
-                        item->email->message_to_me = 1;
-                    } else {
-                        DEBUG_EMAIL(("False\n"));
-                        item->email->message_to_me = 0;
-                    }
+                    LIST_COPY_EMAIL_BOOL("My address in TO field", item->email->message_to_me);
                     break;
                 case 0x0058: // PR_MESSAGE_CC_ME
                     // this user is listed explicitly in the CC address
-                    DEBUG_EMAIL(("My address in CC field - "));
-                    MALLOC_EMAIL(item);
-                    if (*(int16_t*)list->items[x]->data) {
-                        DEBUG_EMAIL(("True\n"));
-                        item->email->message_cc_me = 1;
-                    } else {
-                        DEBUG_EMAIL(("False\n"));
-                        item->email->message_cc_me = 0;
-                    }
+                    LIST_COPY_EMAIL_BOOL("My address in CC field", item->email->message_cc_me);
                     break;
                 case 0x0059: // PR_MESSAGE_RECIP_ME
                     // this user appears in TO, CC or BCC address list
-                    DEBUG_EMAIL(("Message addressed to me - "));
-                    MALLOC_EMAIL(item);
-                    if (*(int16_t*)list->items[x]->data) {
-                        DEBUG_EMAIL(("True\n"));
-                        item->email->message_recip_me = 1;
-                    } else {
-                        DEBUG_EMAIL(("False\n"));
-                        item->email->message_recip_me = 0;
-                    }
+                    LIST_COPY_EMAIL_BOOL("Message addressed to me", item->email->message_recip_me);
                     break;
                 case 0x0063: // PR_RESPONSE_REQUESTED
-                    DEBUG_EMAIL(("Response requested - "));
-                    if (*(int16_t*)list->items[x]->data) {
-                        DEBUG_EMAIL(("True\n"));
-                        item->response_requested = 1;
-                    } else {
-                        DEBUG_EMAIL(("False\n"));
-                        item->response_requested = 0;
-                    }
+                    LIST_COPY_BOOL("Response requested", item->response_requested);
                     break;
                 case 0x0064: // PR_SENT_REPRESENTING_ADDRTYPE Access method for Sender Address
-                    DEBUG_EMAIL(("Sent on behalf of address type - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->sender_access, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->sender_access));
+                    LIST_COPY_EMAIL_STR("Sent on behalf of address type", item->email->sender_access);
                     break;
                 case 0x0065: // PR_SENT_REPRESENTING_EMAIL_ADDRESS Sender Address
-                    DEBUG_EMAIL(("Sent on behalf of Address - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->sender_address, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->sender_address));
+                    LIST_COPY_EMAIL_STR("Sent on behalf of address", item->email->sender_address);
                     break;
                 case 0x0070: // PR_CONVERSATION_TOPIC Processed Subject
-                    DEBUG_EMAIL(("Processed Subject (Conversation Topic) - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->proc_subject, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->proc_subject));
+                    LIST_COPY_EMAIL_STR("Processed Subject (Conversation Topic)", item->email->processed_subject);
                     break;
                 case 0x0071: // PR_CONVERSATION_INDEX
                     DEBUG_EMAIL(("Conversation Index - "));
@@ -2117,52 +2046,28 @@
                     DEBUG_EMAIL(("%i\n", item->email->conv_index));
                     break;
                 case 0x0072: // PR_ORIGINAL_DISPLAY_BCC
-                    DEBUG_EMAIL(("Original display bcc - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->original_bcc, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->original_bcc));
+                    LIST_COPY_EMAIL_STR("Original display bcc", item->email->original_bcc);
                     break;
                 case 0x0073: // PR_ORIGINAL_DISPLAY_CC
-                    DEBUG_EMAIL(("Original display cc - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->original_cc, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->original_cc));
+                    LIST_COPY_EMAIL_STR("Original display cc", item->email->original_cc);
                     break;
                 case 0x0074: // PR_ORIGINAL_DISPLAY_TO
-                    DEBUG_EMAIL(("Original display to - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->original_to, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->original_to));
+                    LIST_COPY_EMAIL_STR("Original display to", item->email->original_to);
                     break;
                 case 0x0075: // PR_RECEIVED_BY_ADDRTYPE Recipient Access Method
-                    DEBUG_EMAIL(("Received by Address type - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->recip_access, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->recip_access));
+                    LIST_COPY_EMAIL_STR("Received by Address type", item->email->recip_access);
                     break;
                 case 0x0076: // PR_RECEIVED_BY_EMAIL_ADDRESS Recipient Address
-                    DEBUG_EMAIL(("Received by Address - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->recip_address, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->recip_address));
+                    LIST_COPY_EMAIL_STR("Received by Address", item->email->recip_address);
                     break;
                 case 0x0077: // PR_RCVD_REPRESENTING_ADDRTYPE Recipient Access Method 2
-                    DEBUG_EMAIL(("Received on behalf of Address type - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->recip2_access, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->recip2_access));
+                    LIST_COPY_EMAIL_STR("Received on behalf of Address type", item->email->recip2_access);
                     break;
                 case 0x0078: // PR_RCVD_REPRESENTING_EMAIL_ADDRESS Recipient Address 2
-                    DEBUG_EMAIL(("Received on behalf of Address -"));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->recip2_address, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->recip2_address));
+                    LIST_COPY_EMAIL_STR("Received on behalf of Address", item->email->recip2_address);
                     break;
                 case 0x007D: // PR_TRANSPORT_MESSAGE_HEADERS Internet Header
-                    DEBUG_EMAIL(("Internet Header - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->header, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->header));
+                    LIST_COPY_EMAIL_STR("Internet Header", item->email->header);
                     break;
                 case 0x0C04: // PR_NDR_REASON_CODE
                     MALLOC_EMAIL(item);
@@ -2180,22 +2085,9 @@
                     break;
                 case 0x0C06: // PR_NON_RECEIPT_NOTIFICATION_REQUESTED
                     DEBUG_EMAIL(("Non-Receipt Notification Requested - (ignored) - "));
-                    if (*(int16_t*)list->items[x]->data) {
-                        DEBUG_EMAIL(("True\n"));
-                    } else {
-                        DEBUG_EMAIL(("False\n"));
-                    }
                     break;
                 case 0x0C17: // PR_REPLY_REQUESTED
-                    DEBUG_EMAIL(("Reply Requested - "));
-                    MALLOC_EMAIL(item);
-                    if (*(int16_t*)list->items[x]->data) {
-                        DEBUG_EMAIL(("True\n"));
-                        item->email->reply_requested = 1;
-                    } else {
-                        DEBUG_EMAIL(("False\n"));
-                        item->email->reply_requested = 0;
-                    }
+                    LIST_COPY_EMAIL_BOOL("Reply Requested", item->email->reply_requested);
                     break;
                 case 0x0C19: // PR_SENDER_ENTRYID Sender Structure 2
                     DEBUG_EMAIL(("Sender Structure 2 -- NOT HANDLED\n"));
@@ -2204,28 +2096,16 @@
                     DEBUG_EMAIL(("Name of Sender Structure 2 -- NOT HANDLED\n"));
                     break;
                 case 0x0C1B: // PR_SUPPLEMENTARY_INFO
-                    DEBUG_EMAIL(("Supplementary info - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->supplementary_info, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->supplementary_info));
+                    LIST_COPY_EMAIL_STR("Supplementary info", item->email->supplementary_info);
                     break;
                 case 0x0C1D: // PR_SENDER_SEARCH_KEY Name of Sender Address 2
-                    DEBUG_EMAIL(("Name of Sender Address 2 (Sender search key) - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->outlook_sender2, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->outlook_sender2));
+                    LIST_COPY_EMAIL_STR("Name of Sender Address 2 (Sender search key)", item->email->outlook_sender2);
                     break;
                 case 0x0C1E: // PR_SENDER_ADDRTYPE Sender Address 2 access method
-                    DEBUG_EMAIL(("Sender Address type - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->sender2_access, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->sender2_access));
+                    LIST_COPY_EMAIL_STR("Sender Address type", item->email->sender2_access);
                     break;
                 case 0x0C1F: // PR_SENDER_EMAIL_ADDRESS Sender Address 2
-                    DEBUG_EMAIL(("Sender Address - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->sender2_address, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->sender2_address));
+                    LIST_COPY_EMAIL_STR("Sender Address", item->email->sender2_address);
                     break;
                 case 0x0C20: // PR_NDR_STATUS_CODE
                     MALLOC_EMAIL(item);
@@ -2235,34 +2115,16 @@
                     DEBUG_EMAIL(("NDR status code - [%i]\n", (int)t));
                     break;
                 case 0x0E01: // PR_DELETE_AFTER_SUBMIT
-                    // I am not too sure how this works
-                    DEBUG_EMAIL(("Delete after submit - "));
-                    MALLOC_EMAIL(item);
-                    if (*(int16_t*)list->items[x]->data) {
-                        DEBUG_EMAIL(("True\n"));
-                        item->email->delete_after_submit = 1;
-                    } else {
-                        DEBUG_EMAIL(("False\n"));
-                        item->email->delete_after_submit = 0;
-                    }
+                    LIST_COPY_EMAIL_BOOL("Delete after submit", item->email->delete_after_submit);
                     break;
                 case 0x0E02: // PR_DISPLAY_BCC BCC Addresses
-                    DEBUG_EMAIL(("Display BCC Addresses - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->bcc_address, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->bcc_address));
+                    LIST_COPY_EMAIL_STR("Display BCC Addresses", item->email->bcc_address);
                     break;
                 case 0x0E03: // PR_DISPLAY_CC CC Addresses
-                    DEBUG_EMAIL(("Display CC Addresses - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->cc_address, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->cc_address));
+                    LIST_COPY_EMAIL_STR("Display CC Addresses", item->email->cc_address);
                     break;
                 case 0x0E04: // PR_DISPLAY_TO Address Sent-To
-                    DEBUG_EMAIL(("Display Sent-To Address - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->sentto_address, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->sentto_address));
+                    LIST_COPY_EMAIL_STR("Display Sent-To Address", item->email->sentto_address);
                     break;
                 case 0x0E06: // PR_MESSAGE_DELIVERY_TIME Date 3 - Email Arrival Date
                     DEBUG_EMAIL(("Date 3 (Delivery Time) - "));
@@ -2306,15 +2168,7 @@
                     // False means rtf version is more up-to-date than text body
                     // if this value doesn't exist, text body is more up-to-date than rtf and
                     //   cannot update to the rtf
-                    DEBUG_EMAIL(("Compressed RTF in Sync - "));
-                    MALLOC_EMAIL(item);
-                    if (*(int16_t*)list->items[x]->data) {
-                        DEBUG_EMAIL(("True\n"));
-                        item->email->rtf_in_sync = 1;
-                    } else {
-                        DEBUG_EMAIL(("False\n"));
-                        item->email->rtf_in_sync = 0;
-                    }
+                    LIST_COPY_EMAIL_BOOL("Compressed RTF in Sync", item->email->rtf_in_sync);
                     break;
                 case 0x0E20: // PR_ATTACH_SIZE binary Attachment data in record
                     DEBUG_EMAIL(("Attachment Size - "));
@@ -2332,19 +2186,10 @@
                     DEBUG_EMAIL(("\n"));
                     break;
                 case 0x1000: // PR_BODY
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->body, (char*));
-                    item->email->body_was_unicode = (list->items[x]->type == 0x1f) ? 1 : 0;
-                    DEBUG_EMAIL(("Plain Text body %s - \n%s\n", (item->email->body_was_unicode) ? "unicode" : "sbcs",
-                                                               item->email->body));
+                    LIST_COPY_EMAIL_STR("Plain Text body", item->body);
                     break;
                 case 0x1001: // PR_REPORT_TEXT
-                    DEBUG_EMAIL(("Report Text - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->report_text, (char*));
-                    item->email->report_was_unicode = (list->items[x]->type == 0x1f) ? 1 : 0;
-                    DEBUG_EMAIL(("Report Text %s - \n%s\n", (item->email->report_was_unicode) ? "unicode" : "sbcs",
-                                                               item->email->report_text));
+                    LIST_COPY_EMAIL_STR("Report Text", item->email->report_text);
                     break;
                 case 0x1006: // PR_RTF_SYNC_BODY_CRC
                     DEBUG_EMAIL(("RTF Sync Body CRC - "));
@@ -2365,10 +2210,7 @@
                 case 0x1008: // PR_RTF_SYNC_BODY_TAG
                     // the first couple of lines of RTF body so that after modification, then beginning can
                     // once again be found
-                    DEBUG_EMAIL(("RTF Sync body tag - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->rtf_body_tag, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->rtf_body_tag));
+                    LIST_COPY_EMAIL_STR("RTF Sync body tag", item->email->rtf_body_tag);
                     break;
                 case 0x1009: // PR_RTF_COMPRESSED
                     // rtf data is lzw compressed
@@ -2392,52 +2234,28 @@
                     DEBUG_EMAIL(("%i\n", item->email->rtf_ws_trailing_count));
                     break;
                 case 0x1013: // HTML body
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->htmlbody, (char*));
-                    item->email->htmlbody_was_unicode = (list->items[x]->type == 0x1f) ? 1 : 0;
-                    DEBUG_EMAIL(("HTML body %s - \n%s\n", (item->email->htmlbody_was_unicode) ? "unicode" : "sbcs",
-                                                          item->email->htmlbody));
+                    LIST_COPY_EMAIL_STR("HTML body", item->email->htmlbody);
                     break;
                 case 0x1035: // Message ID
-                    DEBUG_EMAIL(("Message ID - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->messageid, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->messageid));
+                    LIST_COPY_EMAIL_STR("Message ID", item->email->messageid);
                     break;
                 case 0x1042: // in-reply-to
-                    DEBUG_EMAIL(("In-Reply-To - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->in_reply_to, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->in_reply_to));
+                    LIST_COPY_EMAIL_STR("In-Reply-To", item->email->in_reply_to);
                     break;
                 case 0x1046: // Return Path - this seems to be the message-id of the rfc822 mail that is being returned
-                    DEBUG_EMAIL(("Return Path - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->return_path_address, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->return_path_address));
+                    LIST_COPY_EMAIL_STR("Return Path", item->email->return_path_address);
                     break;
                 case 0x3001: // PR_DISPLAY_NAME File As
-                    DEBUG_EMAIL(("Display Name - "));
-                    LIST_COPY(item->file_as, (char*));
-                    DEBUG_EMAIL(("%s\n", item->file_as));
+                    LIST_COPY_STR("Display Name", item->file_as);
                     break;
                 case 0x3002: // PR_ADDRTYPE
-                    DEBUG_EMAIL(("Address Type - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->address1_transport, (char*));
-                    DEBUG_EMAIL(("|%s|\n", item->contact->address1_transport));
+                    LIST_COPY_CONTACT_STR("Address Type", item->contact->address1_transport);
                     break;
                 case 0x3003: // PR_EMAIL_ADDRESS
-                    // Contact's email address
-                    DEBUG_EMAIL(("Contact Address - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->address1, (char*));
-                    DEBUG_EMAIL(("|%s|\n", item->contact->address1));
+                    LIST_COPY_CONTACT_STR("Contact email Address", item->contact->address1);
                     break;
                 case 0x3004: // PR_COMMENT Comment for item - usually folders
-                    DEBUG_EMAIL(("Comment - "));
-                    LIST_COPY(item->comment, (char*));
-                    DEBUG_EMAIL(("%s\n", item->comment));
+                    LIST_COPY_STR("Comment", item->comment);
                     break;
                 case 0x3007: // PR_CREATION_TIME Date 4 - Creation Date?
                     DEBUG_EMAIL(("Date 4 (Item Creation Date) - "));
@@ -2532,15 +2350,8 @@
                     DEBUG_EMAIL(("%i\n", item->folder->unseen_email_count));
                     break;
                 case 0x360A: // PR_SUBFOLDERS Has children
-                    DEBUG_EMAIL(("Has Subfolders - "));
                     MALLOC_FOLDER(item);
-                    if (*(int16_t*)list->items[x]->data) {
-                        DEBUG_EMAIL(("True\n"));
-                        item->folder->subfolder = 1;
-                    } else {
-                        DEBUG_EMAIL(("False\n"));
-                        item->folder->subfolder = 0;
-                    }
+                    LIST_COPY_BOOL("Has Subfolders", item->folder->subfolder);
                     break;
                 case 0x3613: // PR_CONTAINER_CLASS IPF.x
                     DEBUG_EMAIL(("IPF.x - "));
@@ -2585,10 +2396,8 @@
                     }
                     break;
                 case 0x3704: // PR_ATTACH_FILENAME Attachment filename (8.3)
-                    DEBUG_EMAIL(("Attachment Filename - "));
                     NULL_CHECK(attach);
-                    LIST_COPY(attach->filename1, (char*));
-                    DEBUG_EMAIL(("%s\n", attach->filename1));
+                    LIST_COPY_STR("Attachment Filename", attach->filename1);
                     break;
                 case 0x3705: // PR_ATTACH_METHOD
                     // 0 - No Attachment
@@ -2611,10 +2420,8 @@
                                        (t==5?"Embedded Message":"OLE")))))),t));
                     break;
                 case 0x3707: // PR_ATTACH_LONG_FILENAME Attachment filename (long?)
-                    DEBUG_EMAIL(("Attachment Filename long - "));
                     NULL_CHECK(attach);
-                    LIST_COPY(attach->filename2, (char*));
-                    DEBUG_EMAIL(("%s\n", attach->filename2));
+                    LIST_COPY_STR("Attachment Filename long", attach->filename2);
                     break;
                 case 0x370B: // PR_RENDERING_POSITION
                     // position in characters that the attachment appears in the plain text body
@@ -2625,10 +2432,8 @@
                     DEBUG_EMAIL(("%i [%#x]\n", attach->position));
                     break;
                 case 0x370E: // PR_ATTACH_MIME_TAG Mime type of encoding
-                    DEBUG_EMAIL(("Attachment mime encoding - "));
                     NULL_CHECK(attach);
-                    LIST_COPY(attach->mimetype, (char*));
-                    DEBUG_EMAIL(("%s\n", attach->mimetype));
+                    LIST_COPY_STR("Attachment mime encoding", attach->mimetype);
                     break;
                 case 0x3710: // PR_ATTACH_MIME_SEQUENCE
                     // sequence number for mime parts. Includes body
@@ -2639,113 +2444,55 @@
                     DEBUG_EMAIL(("%i\n", attach->sequence));
                     break;
                 case 0x3A00: // PR_ACCOUNT
-                    DEBUG_EMAIL(("Contact's Account name - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->account_name, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->account_name));
+                    LIST_COPY_CONTACT_STR("Contact's Account name", item->contact->account_name);
                     break;
                 case 0x3A01: // PR_ALTERNATE_RECIPIENT
                     DEBUG_EMAIL(("Contact Alternate Recipient - NOT PROCESSED\n"));
                     break;
                 case 0x3A02: // PR_CALLBACK_TELEPHONE_NUMBER
-                    DEBUG_EMAIL(("Callback telephone number - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->callback_phone, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->callback_phone));
+                    LIST_COPY_CONTACT_STR("Callback telephone number", item->contact->callback_phone);
                     break;
                 case 0x3A03: // PR_CONVERSION_PROHIBITED
-                    DEBUG_EMAIL(("Message Conversion Prohibited - "));
-                    MALLOC_EMAIL(item);
-                    if (*(int16_t*)list->items[x]->data) {
-                        DEBUG_EMAIL(("True\n"));
-                        item->email->conversion_prohib = 1;
-                    } else {
-                        DEBUG_EMAIL(("False\n"));
-                        item->email->conversion_prohib = 0;
-                    }
+                    LIST_COPY_EMAIL_BOOL("Message Conversion Prohibited", item->email->conversion_prohibited);
                     break;
                 case 0x3A05: // PR_GENERATION suffix
-                    DEBUG_EMAIL(("Contacts Suffix - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->suffix, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->suffix));
+                    LIST_COPY_CONTACT_STR("Contacts Suffix", item->contact->suffix);
                     break;
                 case 0x3A06: // PR_GIVEN_NAME Contact's first name
-                    DEBUG_EMAIL(("Contacts First Name - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->first_name, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->first_name));
+                    LIST_COPY_CONTACT_STR("Contacts First Name", item->contact->first_name);
                     break;
                 case 0x3A07: // PR_GOVERNMENT_ID_NUMBER
-                    DEBUG_EMAIL(("Contacts Government ID Number - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->gov_id, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->gov_id));
+                    LIST_COPY_CONTACT_STR("Contacts Government ID Number", item->contact->gov_id);
                     break;
                 case 0x3A08: // PR_BUSINESS_TELEPHONE_NUMBER
-                    DEBUG_EMAIL(("Business Telephone Number - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->business_phone, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->business_phone));
+                    LIST_COPY_CONTACT_STR("Business Telephone Number", item->contact->business_phone);
                     break;
                 case 0x3A09: // PR_HOME_TELEPHONE_NUMBER
-                    DEBUG_EMAIL(("Home Telephone Number - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->home_phone, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->home_phone));
+                    LIST_COPY_CONTACT_STR("Home Telephone Number", item->contact->home_phone);
                     break;
                 case 0x3A0A: // PR_INITIALS Contact's Initials
-                    DEBUG_EMAIL(("Contacts Initials - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->initials, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->initials));
+                    LIST_COPY_CONTACT_STR("Contacts Initials", item->contact->initials);
                     break;
                 case 0x3A0B: // PR_KEYWORD
-                    DEBUG_EMAIL(("Keyword - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->keyword, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->keyword));
+                    LIST_COPY_CONTACT_STR("Keyword", item->contact->keyword);
                     break;
                 case 0x3A0C: // PR_LANGUAGE
-                    DEBUG_EMAIL(("Contact's Language - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->language, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->language));
+                    LIST_COPY_CONTACT_STR("Contact's Language", item->contact->language);
                     break;
                 case 0x3A0D: // PR_LOCATION
-                    DEBUG_EMAIL(("Contact's Location - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->location, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->location));
+                    LIST_COPY_CONTACT_STR("Contact's Location", item->contact->location);
                     break;
                 case 0x3A0E: // PR_MAIL_PERMISSION - Can the recipient receive and send email
-                    DEBUG_EMAIL(("Mail Permission - "));
-                    MALLOC_CONTACT(item);
-                    if (*(int16_t*)list->items[x]->data) {
-                        DEBUG_EMAIL(("True\n"));
-                        item->contact->mail_permission = 1;
-                    } else {
-                        DEBUG_EMAIL(("False\n"));
-                        item->contact->mail_permission = 0;
-                    }
+                    LIST_COPY_CONTACT_BOOL("Mail Permission", item->contact->mail_permission);
                     break;
                 case 0x3A0F: // PR_MHS_COMMON_NAME
-                    DEBUG_EMAIL(("MHS Common Name - "));
-                    MALLOC_EMAIL(item);
-                    LIST_COPY(item->email->common_name, (char*));
-                    DEBUG_EMAIL(("%s\n", item->email->common_name));
+                    LIST_COPY_CONTACT_STR("MHS Common Name", item->contact->common_name);
                     break;
                 case 0x3A10: // PR_ORGANIZATIONAL_ID_NUMBER
-                    DEBUG_EMAIL(("Organizational ID # - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->org_id, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->org_id));
+                    LIST_COPY_CONTACT_STR("Organizational ID #", item->contact->org_id);
                     break;
                 case 0x3A11: // PR_SURNAME Contact's Surname
-                    DEBUG_EMAIL(("Contacts Surname - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->surname, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->surname));
+                    LIST_COPY_CONTACT_STR("Contacts Surname", item->contact->surname);
                     break;
                 case 0x3A12: // PR_ORIGINAL_ENTRY_ID
                     DEBUG_EMAIL(("Original Entry ID - NOT PROCESSED\n"));
@@ -2757,180 +2504,91 @@
                     DEBUG_EMAIL(("Original Search Key - NOT PROCESSED\n"));
                     break;
                 case 0x3A15: // PR_POSTAL_ADDRESS
-                    DEBUG_EMAIL(("Default Postal Address - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->def_postal_address, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->def_postal_address));
+                    LIST_COPY_CONTACT_STR("Default Postal Address", item->contact->def_postal_address);
                     break;
                 case 0x3A16: // PR_COMPANY_NAME
-                    DEBUG_EMAIL(("Company Name - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->company_name, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->company_name));
+                    LIST_COPY_CONTACT_STR("Company Name", item->contact->company_name);
                     break;
                 case 0x3A17: // PR_TITLE - Job Title
-                    DEBUG_EMAIL(("Job Title - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->job_title, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->job_title));
+                    LIST_COPY_CONTACT_STR("Job Title", item->contact->job_title);
                     break;
                 case 0x3A18: // PR_DEPARTMENT_NAME
-                    DEBUG_EMAIL(("Department Name - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->department, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->department));
+                    LIST_COPY_CONTACT_STR("Department Name", item->contact->department);
                     break;
                 case 0x3A19: // PR_OFFICE_LOCATION
-                    DEBUG_EMAIL(("Office Location - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->office_loc, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->office_loc));
+                    LIST_COPY_CONTACT_STR("Office Location", item->contact->office_loc);
                     break;
                 case 0x3A1A: // PR_PRIMARY_TELEPHONE_NUMBER
-                    DEBUG_EMAIL(("Primary Telephone - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->primary_phone, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->primary_phone));
+                    LIST_COPY_CONTACT_STR("Primary Telephone", item->contact->primary_phone);
                     break;
                 case 0x3A1B: // PR_BUSINESS2_TELEPHONE_NUMBER
-                    DEBUG_EMAIL(("Business Phone Number 2 - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->business_phone2, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->business_phone2));
+                    LIST_COPY_CONTACT_STR("Business Phone Number 2", item->contact->business_phone2);
                     break;
                 case 0x3A1C: // PR_MOBILE_TELEPHONE_NUMBER
-                    DEBUG_EMAIL(("Mobile Phone Number - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->mobile_phone, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->mobile_phone));
+                    LIST_COPY_CONTACT_STR("Mobile Phone Number", item->contact->mobile_phone);
                     break;
                 case 0x3A1D: // PR_RADIO_TELEPHONE_NUMBER
-                    DEBUG_EMAIL(("Radio Phone Number - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->radio_phone, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->radio_phone));
+                    LIST_COPY_CONTACT_STR("Radio Phone Number", item->contact->radio_phone);
                     break;
                 case 0x3A1E: // PR_CAR_TELEPHONE_NUMBER
-                    DEBUG_EMAIL(("Car Phone Number - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->car_phone, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->car_phone));
+                    LIST_COPY_CONTACT_STR("Car Phone Number", item->contact->car_phone);
                     break;
                 case 0x3A1F: // PR_OTHER_TELEPHONE_NUMBER
-                    DEBUG_EMAIL(("Other Phone Number - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->other_phone, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->other_phone));
+                    LIST_COPY_CONTACT_STR("Other Phone Number", item->contact->other_phone);
                     break;
                 case 0x3A20: // PR_TRANSMITTABLE_DISPLAY_NAME
-                    DEBUG_EMAIL(("Transmittable Display Name - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->transmittable_display_name, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->transmittable_display_name));
+                    LIST_COPY_CONTACT_STR("Transmittable Display Name", item->contact->transmittable_display_name);
                     break;
                 case 0x3A21: // PR_PAGER_TELEPHONE_NUMBER
-                    DEBUG_EMAIL(("Pager Phone Number - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->pager_phone, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->pager_phone));
+                    LIST_COPY_CONTACT_STR("Pager Phone Number", item->contact->pager_phone);
                     break;
                 case 0x3A22: // PR_USER_CERTIFICATE
                     DEBUG_EMAIL(("User Certificate - NOT PROCESSED"));
                     break;
                 case 0x3A23: // PR_PRIMARY_FAX_NUMBER
-                    DEBUG_EMAIL(("Primary Fax Number - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->primary_fax, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->primary_fax));
+                    LIST_COPY_CONTACT_STR("Primary Fax Number", item->contact->primary_fax);
                     break;
                 case 0x3A24: // PR_BUSINESS_FAX_NUMBER
-                    DEBUG_EMAIL(("Business Fax Number - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->business_fax, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->business_fax));
+                    LIST_COPY_CONTACT_STR("Business Fax Number", item->contact->business_fax);
                     break;
                 case 0x3A25: // PR_HOME_FAX_NUMBER
-                    DEBUG_EMAIL(("Home Fax Number - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->home_fax, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->home_fax));
+                    LIST_COPY_CONTACT_STR("Home Fax Number", item->contact->home_fax);
                     break;
                 case 0x3A26: // PR_BUSINESS_ADDRESS_COUNTRY
-                    DEBUG_EMAIL(("Business Address Country - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->business_country, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->business_country));
+                    LIST_COPY_CONTACT_STR("Business Address Country", item->contact->business_country);
                     break;
                 case 0x3A27: // PR_BUSINESS_ADDRESS_CITY
-                    DEBUG_EMAIL(("Business Address City - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->business_city, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->business_city));
+                    LIST_COPY_CONTACT_STR("Business Address City", item->contact->business_city);
                     break;
                 case 0x3A28: // PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE
-                    DEBUG_EMAIL(("Business Address State - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->business_state, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->business_state));
+                    LIST_COPY_CONTACT_STR("Business Address State", item->contact->business_state);
                     break;
                 case 0x3A29: // PR_BUSINESS_ADDRESS_STREET
-                    DEBUG_EMAIL(("Business Address Street - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->business_street, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->business_street));
+                    LIST_COPY_CONTACT_STR("Business Address Street", item->contact->business_street);
                     break;
                 case 0x3A2A: // PR_BUSINESS_POSTAL_CODE
-                    DEBUG_EMAIL(("Business Postal Code - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->business_postal_code, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->business_postal_code));
+                    LIST_COPY_CONTACT_STR("Business Postal Code", item->contact->business_postal_code);
                     break;
                 case 0x3A2B: // PR_BUSINESS_PO_BOX
-                    DEBUG_EMAIL(("Business PO Box - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->business_po_box, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->business_po_box));
+                    LIST_COPY_CONTACT_STR("Business PO Box", item->contact->business_po_box);
                     break;
                 case 0x3A2C: // PR_TELEX_NUMBER
-                    DEBUG_EMAIL(("Telex Number - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->telex, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->telex));
+                    LIST_COPY_CONTACT_STR("Telex Number", item->contact->telex);
                     break;
                 case 0x3A2D: // PR_ISDN_NUMBER
-                    DEBUG_EMAIL(("ISDN Number - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->isdn_phone, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->isdn_phone));
+                    LIST_COPY_CONTACT_STR("ISDN Number", item->contact->isdn_phone);
                     break;
                 case 0x3A2E: // PR_ASSISTANT_TELEPHONE_NUMBER
-                    DEBUG_EMAIL(("Assistant Phone Number - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->assistant_phone, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->assistant_phone));
+                    LIST_COPY_CONTACT_STR("Assistant Phone Number", item->contact->assistant_phone);
                     break;
                 case 0x3A2F: // PR_HOME2_TELEPHONE_NUMBER
-                    DEBUG_EMAIL(("Home Phone 2 - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->home_phone2, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->home_phone2));
+                    LIST_COPY_CONTACT_STR("Home Phone 2", item->contact->home_phone2);
                     break;
                 case 0x3A30: // PR_ASSISTANT
-                    DEBUG_EMAIL(("Assistant's Name - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->assistant_name, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->assistant_name));
+                    LIST_COPY_CONTACT_STR("Assistant's Name", item->contact->assistant_name);
                     break;
                 case 0x3A40: // PR_SEND_RICH_INFO
-                    DEBUG_EMAIL(("Can receive Rich Text - "));
-                    MALLOC_CONTACT(item);
-                    if (*(int16_t*)list->items[x]->data) {
-                        DEBUG_EMAIL(("True\n"));
-                        item->contact->rich_text = 1;
-                    } else {
-                        DEBUG_EMAIL(("False\n"));
-                        item->contact->rich_text = 0;
-                    }
+                    LIST_COPY_CONTACT_BOOL("Can receive Rich Text", item->contact->rich_text);
                     break;
                 case 0x3A41: // PR_WEDDING_ANNIVERSARY
                     DEBUG_EMAIL(("Wedding Anniversary - "));
@@ -2945,64 +2603,34 @@
                     DEBUG_EMAIL(("%s\n", fileTimeToAscii(item->contact->birthday)));
                     break;
                 case 0x3A43: // PR_HOBBIES
-                    DEBUG_EMAIL(("Hobbies - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->hobbies, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->hobbies));
+                    LIST_COPY_CONTACT_STR("Hobbies", item->contact->hobbies);
                     break;
                 case 0x3A44: // PR_MIDDLE_NAME
-                    DEBUG_EMAIL(("Middle Name - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->middle_name, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->middle_name));
+                    LIST_COPY_CONTACT_STR("Middle Name", item->contact->middle_name);
                     break;
                 case 0x3A45: // PR_DISPLAY_NAME_PREFIX
-                    DEBUG_EMAIL(("Display Name Prefix (Title) - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->display_name_prefix, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->display_name_prefix));
+                    LIST_COPY_CONTACT_STR("Display Name Prefix (Title)", item->contact->display_name_prefix);
                     break;
                 case 0x3A46: // PR_PROFESSION
-                    DEBUG_EMAIL(("Profession - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->profession, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->profession));
+                    LIST_COPY_CONTACT_STR("Profession", item->contact->profession);
                     break;
                 case 0x3A47: // PR_PREFERRED_BY_NAME
-                    DEBUG_EMAIL(("Preferred By Name - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->pref_name, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->pref_name));
+                    LIST_COPY_CONTACT_STR("Preferred By Name", item->contact->pref_name);
                     break;
                 case 0x3A48: // PR_SPOUSE_NAME
-                    DEBUG_EMAIL(("Spouse's Name - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->spouse_name, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->spouse_name));
+                    LIST_COPY_CONTACT_STR("Spouse's Name", item->contact->spouse_name);
                     break;
                 case 0x3A49: // PR_COMPUTER_NETWORK_NAME
-                    DEBUG_EMAIL(("Computer Network Name - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->computer_name, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->computer_name));
+                    LIST_COPY_CONTACT_STR("Computer Network Name", item->contact->computer_name);
                     break;
                 case 0x3A4A: // PR_CUSTOMER_ID
-                    DEBUG_EMAIL(("Customer ID - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->customer_id, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->customer_id));
+                    LIST_COPY_CONTACT_STR("Customer ID", item->contact->customer_id);
                     break;
                 case 0x3A4B: // PR_TTYTDD_PHONE_NUMBER
-                    DEBUG_EMAIL(("TTY/TDD Phone - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->ttytdd_phone, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->ttytdd_phone));
+                    LIST_COPY_CONTACT_STR("TTY/TDD Phone", item->contact->ttytdd_phone);
                     break;
                 case 0x3A4C: // PR_FTP_SITE
-                    DEBUG_EMAIL(("Ftp Site - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->ftp_site, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->ftp_site));
+                    LIST_COPY_CONTACT_STR("Ftp Site", item->contact->ftp_site);
                     break;
                 case 0x3A4D: // PR_GENDER
                     DEBUG_EMAIL(("Gender - "));
@@ -3024,109 +2652,58 @@
                     }
                     break;
                 case 0x3A4E: // PR_MANAGER_NAME
-                    DEBUG_EMAIL(("Manager's Name - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->manager_name, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->manager_name));
+                    LIST_COPY_CONTACT_STR("Manager's Name", item->contact->manager_name);
                     break;
                 case 0x3A4F: // PR_NICKNAME
-                    DEBUG_EMAIL(("Nickname - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->nickname, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->nickname));
+                    LIST_COPY_CONTACT_STR("Nickname", item->contact->nickname);
                     break;
                 case 0x3A50: // PR_PERSONAL_HOME_PAGE
-                    DEBUG_EMAIL(("Personal Home Page - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->personal_homepage, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->personal_homepage));
+                    LIST_COPY_CONTACT_STR("Personal Home Page", item->contact->personal_homepage);
                     break;
                 case 0x3A51: // PR_BUSINESS_HOME_PAGE
-                    DEBUG_EMAIL(("Business Home Page - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->business_homepage, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->business_homepage));
+                    LIST_COPY_CONTACT_STR("Business Home Page", item->contact->business_homepage);
                     break;
                 case 0x3A57: // PR_COMPANY_MAIN_PHONE_NUMBER
-                    DEBUG_EMAIL(("Company Main Phone - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->company_main_phone, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->company_main_phone));
+                    LIST_COPY_CONTACT_STR("Company Main Phone", item->contact->company_main_phone);
                     break;
                 case 0x3A58: // PR_CHILDRENS_NAMES
                     DEBUG_EMAIL(("Children's Names - NOT PROCESSED\n"));
                     break;
                 case 0x3A59: // PR_HOME_ADDRESS_CITY
-                    DEBUG_EMAIL(("Home Address City - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->home_city, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->home_city));
+                    LIST_COPY_CONTACT_STR("Home Address City", item->contact->home_city);
                     break;
                 case 0x3A5A: // PR_HOME_ADDRESS_COUNTRY
-                    DEBUG_EMAIL(("Home Address Country - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->home_country, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->home_country));
+                    LIST_COPY_CONTACT_STR("Home Address Country", item->contact->home_country);
                     break;
                 case 0x3A5B: // PR_HOME_ADDRESS_POSTAL_CODE
-                    DEBUG_EMAIL(("Home Address Postal Code - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->home_postal_code, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->home_postal_code));
+                    LIST_COPY_CONTACT_STR("Home Address Postal Code", item->contact->home_postal_code);
                     break;
                 case 0x3A5C: // PR_HOME_ADDRESS_STATE_OR_PROVINCE
-                    DEBUG_EMAIL(("Home Address State or Province - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->home_state, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->home_state));
+                    LIST_COPY_CONTACT_STR("Home Address State or Province", item->contact->home_state);
                     break;
                 case 0x3A5D: // PR_HOME_ADDRESS_STREET
-                    DEBUG_EMAIL(("Home Address Street - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->home_street, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->home_street));
+                    LIST_COPY_CONTACT_STR("Home Address Street", item->contact->home_street);
                     break;
                 case 0x3A5E: // PR_HOME_ADDRESS_POST_OFFICE_BOX
-                    DEBUG_EMAIL(("Home Address Post Office Box - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->home_po_box, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->home_po_box));
+                    LIST_COPY_CONTACT_STR("Home Address Post Office Box", item->contact->home_po_box);
                     break;
                 case 0x3A5F: // PR_OTHER_ADDRESS_CITY
-                    DEBUG_EMAIL(("Other Address City - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->other_city, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->other_city));
+                    LIST_COPY_CONTACT_STR("Other Address City", item->contact->other_city);
                     break;
                 case 0x3A60: // PR_OTHER_ADDRESS_COUNTRY
-                    DEBUG_EMAIL(("Other Address Country - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->other_country, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->other_country));
+                    LIST_COPY_CONTACT_STR("Other Address Country", item->contact->other_country);
                     break;
                 case 0x3A61: // PR_OTHER_ADDRESS_POSTAL_CODE
-                    DEBUG_EMAIL(("Other Address Postal Code - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->other_postal_code, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->other_postal_code));
+                    LIST_COPY_CONTACT_STR("Other Address Postal Code", item->contact->other_postal_code);
                     break;
                 case 0x3A62: // PR_OTHER_ADDRESS_STATE_OR_PROVINCE
-                    DEBUG_EMAIL(("Other Address State - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->other_state, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->other_state));
+                    LIST_COPY_CONTACT_STR("Other Address State", item->contact->other_state);
                     break;
                 case 0x3A63: // PR_OTHER_ADDRESS_STREET
-                    DEBUG_EMAIL(("Other Address Street - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->other_street, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->other_street));
+                    LIST_COPY_CONTACT_STR("Other Address Street", item->contact->other_street);
                     break;
                 case 0x3A64: // PR_OTHER_ADDRESS_POST_OFFICE_BOX
-                    DEBUG_EMAIL(("Other Address Post Office box - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->other_po_box, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->other_po_box));
+                    LIST_COPY_CONTACT_STR("Other Address Post Office box", item->contact->other_po_box);
                     break;
                 case 0x3FDE: // PR_INTERNET_CPID
                     memcpy(&(item->internet_cpid), list->items[x]->data, sizeof(item->internet_cpid));
@@ -3191,142 +2768,73 @@
                     DEBUG_EMAIL_HEXPRINT((char*)item->message_store->top_of_folder->entryid, 16);
                     break;
                 case 0x8005: // Contact's Fullname
-                    DEBUG_EMAIL(("Contact Fullname - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->fullname, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->fullname));
+                    LIST_COPY_CONTACT_STR("Contact Fullname", item->contact->fullname);
                     break;
                 case 0x801A: // Full Home Address
-                    DEBUG_EMAIL(("Home Address - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->home_address, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->home_address));
+                    LIST_COPY_CONTACT_STR("Home Address", item->contact->home_address);
                     break;
                 case 0x801B: // Full Business Address
-                    DEBUG_EMAIL(("Business Address - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->business_address, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->business_address));
+                    LIST_COPY_CONTACT_STR("Business Address", item->contact->business_address);
                     break;
                 case 0x801C: // Full Other Address
-                    DEBUG_EMAIL(("Other Address - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->other_address, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->other_address));
+                    LIST_COPY_CONTACT_STR("Other Address", item->contact->other_address);
                     break;
                 case 0x8045: // Work address street
-                    DEBUG_EMAIL(("Work address street - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->work_address_street, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->work_address_street));
+                    LIST_COPY_CONTACT_STR("Work address street", item->contact->work_address_street);
                     break;
                 case 0x8046: // Work address city
-                    DEBUG_EMAIL(("Work address city - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->work_address_city, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->work_address_city));
+                    LIST_COPY_CONTACT_STR("Work address city", item->contact->work_address_city);
                     break;
                 case 0x8047: // Work address state
-                    DEBUG_EMAIL(("Work address state - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->work_address_state, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->work_address_state));
+                    LIST_COPY_CONTACT_STR("Work address state", item->contact->work_address_state);
                     break;
                 case 0x8048: // Work address postalcode
-                    DEBUG_EMAIL(("Work address postalcode - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->work_address_postalcode, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->work_address_postalcode));
+                    LIST_COPY_CONTACT_STR("Work address postalcode", item->contact->work_address_postalcode);
                     break;
                 case 0x8049: // Work address country
-                    DEBUG_EMAIL(("Work address country - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->work_address_country, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->work_address_country));
+                    LIST_COPY_CONTACT_STR("Work address country", item->contact->work_address_country);
                     break;
                 case 0x804A: // Work address postofficebox
-                    DEBUG_EMAIL(("Work address postofficebox - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->work_address_postofficebox, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->work_address_postofficebox));
+                    LIST_COPY_CONTACT_STR("Work address postofficebox", item->contact->work_address_postofficebox);
                     break;
                 case 0x8082: // Email Address 1 Transport
-                    DEBUG_EMAIL(("Email Address 1 Transport - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->address1_transport, (char*));
-                    DEBUG_EMAIL(("|%s|\n", item->contact->address1_transport));
+                    LIST_COPY_CONTACT_STR("Email Address 1 Transport", item->contact->address1_transport);
                     break;
                 case 0x8083: // Email Address 1 Address
-                    DEBUG_EMAIL(("Email Address 1 Address - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->address1, (char*));
-                    DEBUG_EMAIL(("|%s|\n", item->contact->address1));
+                    LIST_COPY_CONTACT_STR("Email Address 1 Address", item->contact->address1);
                     break;
                 case 0x8084: // Email Address 1 Description
-                    DEBUG_EMAIL(("Email Address 1 Description - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->address1_desc, (char*));
-                    DEBUG_EMAIL(("|%s|\n", item->contact->address1_desc));
+                    LIST_COPY_CONTACT_STR("Email Address 1 Description", item->contact->address1_desc);
                     break;
                 case 0x8085: // Email Address 1 Record
-                    DEBUG_EMAIL(("Email Address 1 Record - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->address1a, (char*));
-                    DEBUG_EMAIL(("|%s|\n", item->contact->address1a));
+                    LIST_COPY_CONTACT_STR("Email Address 1 Record", item->contact->address1a);
                     break;
                 case 0x8092: // Email Address 2 Transport
-                    DEBUG_EMAIL(("Email Address 2 Transport - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->address2_transport, (char*));
-                    DEBUG_EMAIL(("|%s|\n", item->contact->address2_transport));
+                    LIST_COPY_CONTACT_STR("Email Address 2 Transport", item->contact->address2_transport);
                     break;
                 case 0x8093: // Email Address 2 Address
-                    DEBUG_EMAIL(("Email Address 2 Address - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->address2, (char*));
-                    DEBUG_EMAIL(("|%s|\n", item->contact->address2));
+                    LIST_COPY_CONTACT_STR("Email Address 2 Address", item->contact->address2);
                     break;
                 case 0x8094: // Email Address 2 Description
-                    DEBUG_EMAIL (("Email Address 2 Description - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->address2_desc, (char*));
-                    DEBUG_EMAIL(("|%s|\n", item->contact->address2_desc));
+                    LIST_COPY_CONTACT_STR("Email Address 2 Description", item->contact->address2_desc);
                     break;
                 case 0x8095: // Email Address 2 Record
-                    DEBUG_EMAIL(("Email Address 2 Record - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->address2a, (char*));
-                    DEBUG_EMAIL(("|%s|\n", item->contact->address2a));
+                    LIST_COPY_CONTACT_STR("Email Address 2 Record", item->contact->address2a);
                     break;
                 case 0x80A2: // Email Address 3 Transport
-                    DEBUG_EMAIL (("Email Address 3 Transport - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->address3_transport, (char*));
-                    DEBUG_EMAIL(("|%s|\n", item->contact->address3_transport));
+                    LIST_COPY_CONTACT_STR("Email Address 3 Transport", item->contact->address3_transport);
                     break;
                 case 0x80A3: // Email Address 3 Address
-                    DEBUG_EMAIL(("Email Address 3 Address - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->address3, (char*));
-                    DEBUG_EMAIL(("|%s|\n", item->contact->address3));
+                    LIST_COPY_CONTACT_STR("Email Address 3 Address", item->contact->address3);
                     break;
                 case 0x80A4: // Email Address 3 Description
-                    DEBUG_EMAIL(("Email Address 3 Description - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->address3_desc, (char*));
-                    DEBUG_EMAIL(("|%s|\n", item->contact->address3_desc));
+                    LIST_COPY_CONTACT_STR("Email Address 3 Description", item->contact->address3_desc);
                     break;
                 case 0x80A5: // Email Address 3 Record
-                    DEBUG_EMAIL(("Email Address 3 Record - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->address3a, (char*));
-                    DEBUG_EMAIL(("|%s|\n", item->contact->address3a));
+                    LIST_COPY_CONTACT_STR("Email Address 3 Record", item->contact->address3a);
                     break;
                 case 0x80D8: // Internet Free/Busy
-                    DEBUG_EMAIL(("Internet Free/Busy - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->free_busy_address, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->free_busy_address));
+                    LIST_COPY_CONTACT_STR("Internet Free/Busy", item->contact->free_busy_address);
                     break;
                 case 0x8205: // Show on Free/Busy as
                     // 0: Free
@@ -3351,10 +2859,7 @@
                     }
                     break;
                 case 0x8208: // Location of an appointment
-                    DEBUG_EMAIL(("Appointment Location - "));
-                    MALLOC_APPOINTMENT(item);
-                    LIST_COPY(item->appointment->location, (char*));
-                    DEBUG_EMAIL(("%s\n", item->appointment->location));
+                    LIST_COPY_APPT_STR("Appointment Location", item->appointment->location);
                     break;
                 case 0x820d: // Appointment start
                     DEBUG_EMAIL(("Appointment Date Start - "));
@@ -3399,15 +2904,7 @@
                     }
                     break;
                 case 0x8215: // All day appointment flag
-                    DEBUG_EMAIL(("All day flag - "));
-                    MALLOC_APPOINTMENT(item);
-                    if (*(int16_t*)list->items[x]->data) {
-                        DEBUG_EMAIL(("True\n"));
-                        item->appointment->all_day = 1;
-                    } else {
-                        DEBUG_EMAIL(("False\n"));
-                        item->appointment->all_day = 0;
-                    }
+                    LIST_COPY_APPT_BOOL("All day flag", item->appointment->all_day);
                     break;
                 case 0x8231: // Recurrence type
                     // 1: Daily
@@ -3432,16 +2929,10 @@
                     }
                     break;
                 case 0x8232: // Recurrence description
-                    DEBUG_EMAIL(("Appointment recurrence description - "));
-                    MALLOC_APPOINTMENT(item);
-                    LIST_COPY(item->appointment->recurrence, (char*));
-                    DEBUG_EMAIL(("%s\n", item->appointment->recurrence));
+                    LIST_COPY_APPT_STR("Appointment recurrence description", item->appointment->recurrence);
                     break;
                 case 0x8234: // TimeZone as String
-                    DEBUG_EMAIL(("TimeZone of times - "));
-                    MALLOC_APPOINTMENT(item);
-                    LIST_COPY(item->appointment->timezonestring, (char*));
-                    DEBUG_EMAIL(("%s\n", item->appointment->timezonestring));
+                    LIST_COPY_APPT_STR("TimeZone of times", item->appointment->timezonestring);
                     break;
                 case 0x8235: // Recurrence start date
                     DEBUG_EMAIL(("Recurrence Start Date - "));
@@ -3463,15 +2954,7 @@
                     DEBUG_EMAIL(("%i\n", item->appointment->alarm_minutes));
                     break;
                 case 0x8503: // Reminder alarm
-                    DEBUG_EMAIL(("Reminder alarm - "));
-                    MALLOC_APPOINTMENT(item);
-                    if (*(int16_t*)list->items[x]->data) {
-                        DEBUG_EMAIL(("True\n"));
-                        item->appointment->alarm = 1;
-                    } else {
-                        DEBUG_EMAIL(("False\n"));
-                        item->appointment->alarm = 0;
-                    }
+                    LIST_COPY_APPT_BOOL("Reminder alarm", item->appointment->alarm);
                     break;
                 case 0x8516: // Common start
                     DEBUG_EMAIL(("Common Start Date - "));
@@ -3482,33 +2965,19 @@
                     DEBUG_EMAIL(("%s\n", fileTimeToAscii((FILETIME*)list->items[x]->data)));
                     break;
                 case 0x851f: // Play reminder sound filename
-                    DEBUG_EMAIL(("Appointment reminder sound filename - "));
-                    MALLOC_APPOINTMENT(item);
-                    LIST_COPY(item->appointment->alarm_filename, (char*));
-                    DEBUG_EMAIL(("%s\n", item->appointment->alarm_filename));
+                    LIST_COPY_APPT_STR("Appointment reminder sound filename", item->appointment->alarm_filename);
                     break;
                 case 0x8530: // Followup
-                    DEBUG_EMAIL(("Followup String - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->followup, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->followup));
+                    LIST_COPY_CONTACT_STR("Followup String", item->contact->followup);
                     break;
                 case 0x8534: // Mileage
-                    DEBUG_EMAIL(("Mileage - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->mileage, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->mileage));
+                    LIST_COPY_CONTACT_STR("Mileage", item->contact->mileage);
                     break;
                 case 0x8535: // Billing Information
-                    DEBUG_EMAIL(("Billing Information - "));
-                    MALLOC_CONTACT(item);
-                    LIST_COPY(item->contact->billing_information, (char*));
-                    DEBUG_EMAIL(("%s\n", item->contact->billing_information));
+                    LIST_COPY_CONTACT_STR("Billing Information", item->contact->billing_information);
                     break;
                 case 0x8554: // Outlook Version
-                    DEBUG_EMAIL(("Outlook Version - "));
-                    LIST_COPY(item->outlook_version, (char*));
-                    DEBUG_EMAIL(("%s\n", item->outlook_version));
+                    LIST_COPY_STR("Outlook Version", item->outlook_version);
                     break;
                 case 0x8560: // Appointment Reminder Time
                     DEBUG_EMAIL(("Appointment Reminder Time - "));
@@ -3517,10 +2986,8 @@
                     DEBUG_EMAIL(("%s\n", fileTimeToAscii(item->appointment->reminder)));
                     break;
                 case 0x8700: // Journal Type
-                    DEBUG_EMAIL(("Journal Entry Type - "));
                     MALLOC_JOURNAL(item);
-                    LIST_COPY(item->journal->type, (char*));
-                    DEBUG_EMAIL(("%s\n", item->journal->type));
+                    LIST_COPY_STR("Journal Entry Type", item->journal->type);
                     break;
                 case 0x8706: // Journal Start date/time
                     DEBUG_EMAIL(("Start Timestamp - "));
@@ -3535,10 +3002,8 @@
                     DEBUG_EMAIL(("%s\n", fileTimeToAscii(item->journal->end)));
                     break;
                 case 0x8712: // Title?
-                    DEBUG_EMAIL(("Journal Entry Type - "));
                     MALLOC_JOURNAL(item);
-                    LIST_COPY(item->journal->type, (char*));
-                    DEBUG_EMAIL(("%s\n", item->journal->type));
+                    LIST_COPY_STR("Journal Entry Type", item->journal->type);
                     break;
                 default:
                     if (list->items[x]->type == (uint32_t)0x0002) {
@@ -3647,7 +3112,6 @@
                         list->items[x]->data = NULL;
                     }
             }
-            x++;
         }
         list = list->next;
         if (attach) attach = attach->next;
@@ -3813,9 +3277,9 @@
 void pst_free_attach(pst_item_attach *attach) {
     while (attach) {
         pst_item_attach *t;
-        SAFE_FREE(attach->filename1);
-        SAFE_FREE(attach->filename2);
-        SAFE_FREE(attach->mimetype);
+        SAFE_FREE_STR(attach->filename1);
+        SAFE_FREE_STR(attach->filename2);
+        SAFE_FREE_STR(attach->mimetype);
         SAFE_FREE(attach->data);
         pst_free_id2(attach->id2_head);
         t = attach->next;
@@ -3832,47 +3296,42 @@
     if (item) {
         if (item->email) {
             SAFE_FREE(item->email->arrival_date);
-            SAFE_FREE(item->email->body);
-            SAFE_FREE(item->email->cc_address);
-            SAFE_FREE(item->email->bcc_address);
-            SAFE_FREE(item->email->common_name);
+            SAFE_FREE_STR(item->email->cc_address);
+            SAFE_FREE_STR(item->email->bcc_address);
             SAFE_FREE(item->email->encrypted_body);
             SAFE_FREE(item->email->encrypted_htmlbody);
-            SAFE_FREE(item->email->header);
-            SAFE_FREE(item->email->htmlbody);
-            SAFE_FREE(item->email->in_reply_to);
-            SAFE_FREE(item->email->messageid);
-            SAFE_FREE(item->email->original_bcc);
-            SAFE_FREE(item->email->original_cc);
-            SAFE_FREE(item->email->original_to);
-            SAFE_FREE(item->email->outlook_recipient);
-            SAFE_FREE(item->email->outlook_recipient_name);
-            SAFE_FREE(item->email->outlook_recipient2);
-            SAFE_FREE(item->email->outlook_sender);
-            SAFE_FREE(item->email->outlook_sender_name);
-            SAFE_FREE(item->email->outlook_sender2);
-            SAFE_FREE(item->email->proc_subject);
-            SAFE_FREE(item->email->recip_access);
-            SAFE_FREE(item->email->recip_address);
-            SAFE_FREE(item->email->recip2_access);
-            SAFE_FREE(item->email->recip2_address);
-            SAFE_FREE(item->email->reply_to);
-            SAFE_FREE(item->email->rtf_body_tag);
+            SAFE_FREE_STR(item->email->header);
+            SAFE_FREE_STR(item->email->htmlbody);
+            SAFE_FREE_STR(item->email->in_reply_to);
+            SAFE_FREE_STR(item->email->messageid);
+            SAFE_FREE_STR(item->email->original_bcc);
+            SAFE_FREE_STR(item->email->original_cc);
+            SAFE_FREE_STR(item->email->original_to);
+            SAFE_FREE_STR(item->email->outlook_recipient);
+            SAFE_FREE_STR(item->email->outlook_recipient_name);
+            SAFE_FREE_STR(item->email->outlook_recipient2);
+            SAFE_FREE_STR(item->email->outlook_sender);
+            SAFE_FREE_STR(item->email->outlook_sender_name);
+            SAFE_FREE_STR(item->email->outlook_sender2);
+            SAFE_FREE_STR(item->email->processed_subject);
+            SAFE_FREE_STR(item->email->recip_access);
+            SAFE_FREE_STR(item->email->recip_address);
+            SAFE_FREE_STR(item->email->recip2_access);
+            SAFE_FREE_STR(item->email->recip2_address);
+            SAFE_FREE_STR(item->email->reply_to);
+            SAFE_FREE_STR(item->email->rtf_body_tag);
             SAFE_FREE(item->email->rtf_compressed);
-            SAFE_FREE(item->email->return_path_address);
-            SAFE_FREE(item->email->sender_access);
-            SAFE_FREE(item->email->sender_address);
-            SAFE_FREE(item->email->sender2_access);
-            SAFE_FREE(item->email->sender2_address);
+            SAFE_FREE_STR(item->email->return_path_address);
+            SAFE_FREE_STR(item->email->sender_access);
+            SAFE_FREE_STR(item->email->sender_address);
+            SAFE_FREE_STR(item->email->sender2_access);
+            SAFE_FREE_STR(item->email->sender2_address);
             SAFE_FREE(item->email->sent_date);
             SAFE_FREE(item->email->sentmail_folder);
-            SAFE_FREE(item->email->sentto_address);
-            if (item->email->subject)
-                SAFE_FREE(item->email->subject->subj);
-            SAFE_FREE(item->email->subject);
-            SAFE_FREE(item->email->report_text);
+            SAFE_FREE_STR(item->email->sentto_address);
+            SAFE_FREE_STR(item->email->report_text);
             SAFE_FREE(item->email->report_time);
-            SAFE_FREE(item->email->supplementary_info);
+            SAFE_FREE_STR(item->email->supplementary_info);
             free(item->email);
         }
         if (item->folder) {
@@ -3890,102 +3349,103 @@
             free(item->message_store);
         }
         if (item->contact) {
-            SAFE_FREE(item->contact->access_method);
-            SAFE_FREE(item->contact->account_name);
-            SAFE_FREE(item->contact->address1);
-            SAFE_FREE(item->contact->address1a);
-            SAFE_FREE(item->contact->address1_desc);
-            SAFE_FREE(item->contact->address1_transport);
-            SAFE_FREE(item->contact->address2);
-            SAFE_FREE(item->contact->address2a);
-            SAFE_FREE(item->contact->address2_desc);
-            SAFE_FREE(item->contact->address2_transport);
-            SAFE_FREE(item->contact->address3);
-            SAFE_FREE(item->contact->address3a);
-            SAFE_FREE(item->contact->address3_desc);
-            SAFE_FREE(item->contact->address3_transport);
-            SAFE_FREE(item->contact->assistant_name);
-            SAFE_FREE(item->contact->assistant_phone);
-            SAFE_FREE(item->contact->billing_information);
+            SAFE_FREE_STR(item->contact->access_method);
+            SAFE_FREE_STR(item->contact->account_name);
+            SAFE_FREE_STR(item->contact->address1);
+            SAFE_FREE_STR(item->contact->address1a);
+            SAFE_FREE_STR(item->contact->address1_desc);
+            SAFE_FREE_STR(item->contact->address1_transport);
+            SAFE_FREE_STR(item->contact->address2);
+            SAFE_FREE_STR(item->contact->address2a);
+            SAFE_FREE_STR(item->contact->address2_desc);
+            SAFE_FREE_STR(item->contact->address2_transport);
+            SAFE_FREE_STR(item->contact->address3);
+            SAFE_FREE_STR(item->contact->address3a);
+            SAFE_FREE_STR(item->contact->address3_desc);
+            SAFE_FREE_STR(item->contact->address3_transport);
+            SAFE_FREE_STR(item->contact->assistant_name);
+            SAFE_FREE_STR(item->contact->assistant_phone);
+            SAFE_FREE_STR(item->contact->billing_information);
             SAFE_FREE(item->contact->birthday);
-            SAFE_FREE(item->contact->business_address);
-            SAFE_FREE(item->contact->business_city);
-            SAFE_FREE(item->contact->business_country);
-            SAFE_FREE(item->contact->business_fax);
-            SAFE_FREE(item->contact->business_homepage);
-            SAFE_FREE(item->contact->business_phone);
-            SAFE_FREE(item->contact->business_phone2);
-            SAFE_FREE(item->contact->business_po_box);
-            SAFE_FREE(item->contact->business_postal_code);
-            SAFE_FREE(item->contact->business_state);
-            SAFE_FREE(item->contact->business_street);
-            SAFE_FREE(item->contact->callback_phone);
-            SAFE_FREE(item->contact->car_phone);
-            SAFE_FREE(item->contact->company_main_phone);
-            SAFE_FREE(item->contact->company_name);
-            SAFE_FREE(item->contact->computer_name);
-            SAFE_FREE(item->contact->customer_id);
-            SAFE_FREE(item->contact->def_postal_address);
-            SAFE_FREE(item->contact->department);
-            SAFE_FREE(item->contact->display_name_prefix);
-            SAFE_FREE(item->contact->first_name);
-            SAFE_FREE(item->contact->followup);
-            SAFE_FREE(item->contact->free_busy_address);
-            SAFE_FREE(item->contact->ftp_site);
-            SAFE_FREE(item->contact->fullname);
-            SAFE_FREE(item->contact->gov_id);
-            SAFE_FREE(item->contact->hobbies);
-            SAFE_FREE(item->contact->home_address);
-            SAFE_FREE(item->contact->home_city);
-            SAFE_FREE(item->contact->home_country);
-            SAFE_FREE(item->contact->home_fax);
-            SAFE_FREE(item->contact->home_po_box);
-            SAFE_FREE(item->contact->home_phone);
-            SAFE_FREE(item->contact->home_phone2);
-            SAFE_FREE(item->contact->home_postal_code);
-            SAFE_FREE(item->contact->home_state);
-            SAFE_FREE(item->contact->home_street);
-            SAFE_FREE(item->contact->initials);
-            SAFE_FREE(item->contact->isdn_phone);
-            SAFE_FREE(item->contact->job_title);
-            SAFE_FREE(item->contact->keyword);
-            SAFE_FREE(item->contact->language);
-            SAFE_FREE(item->contact->location);
-            SAFE_FREE(item->contact->manager_name);
-            SAFE_FREE(item->contact->middle_name);
-            SAFE_FREE(item->contact->mileage);
-            SAFE_FREE(item->contact->mobile_phone);
-            SAFE_FREE(item->contact->nickname);
-            SAFE_FREE(item->contact->office_loc);
-            SAFE_FREE(item->contact->org_id);
-            SAFE_FREE(item->contact->other_address);
-            SAFE_FREE(item->contact->other_city);
-            SAFE_FREE(item->contact->other_country);
-            SAFE_FREE(item->contact->other_phone);
-            SAFE_FREE(item->contact->other_po_box);
-            SAFE_FREE(item->contact->other_postal_code);
-            SAFE_FREE(item->contact->other_state);
-            SAFE_FREE(item->contact->other_street);
-            SAFE_FREE(item->contact->pager_phone);
-            SAFE_FREE(item->contact->personal_homepage);
-            SAFE_FREE(item->contact->pref_name);
-            SAFE_FREE(item->contact->primary_fax);
-            SAFE_FREE(item->contact->primary_phone);
-            SAFE_FREE(item->contact->profession);
-            SAFE_FREE(item->contact->radio_phone);
-            SAFE_FREE(item->contact->spouse_name);
-            SAFE_FREE(item->contact->suffix);
-            SAFE_FREE(item->contact->surname);
-            SAFE_FREE(item->contact->telex);
-            SAFE_FREE(item->contact->transmittable_display_name);
-            SAFE_FREE(item->contact->ttytdd_phone);
+            SAFE_FREE_STR(item->contact->business_address);
+            SAFE_FREE_STR(item->contact->business_city);
+            SAFE_FREE_STR(item->contact->business_country);
+            SAFE_FREE_STR(item->contact->business_fax);
+            SAFE_FREE_STR(item->contact->business_homepage);
+            SAFE_FREE_STR(item->contact->business_phone);
+            SAFE_FREE_STR(item->contact->business_phone2);
+            SAFE_FREE_STR(item->contact->business_po_box);
+            SAFE_FREE_STR(item->contact->business_postal_code);
+            SAFE_FREE_STR(item->contact->business_state);
+            SAFE_FREE_STR(item->contact->business_street);
+            SAFE_FREE_STR(item->contact->callback_phone);
+            SAFE_FREE_STR(item->contact->car_phone);
+            SAFE_FREE_STR(item->contact->company_main_phone);
+            SAFE_FREE_STR(item->contact->company_name);
+            SAFE_FREE_STR(item->contact->computer_name);
+            SAFE_FREE_STR(item->contact->customer_id);
+            SAFE_FREE_STR(item->contact->def_postal_address);
+            SAFE_FREE_STR(item->contact->department);
+            SAFE_FREE_STR(item->contact->display_name_prefix);
+            SAFE_FREE_STR(item->contact->first_name);
+            SAFE_FREE_STR(item->contact->followup);
+            SAFE_FREE_STR(item->contact->free_busy_address);
+            SAFE_FREE_STR(item->contact->ftp_site);
+            SAFE_FREE_STR(item->contact->fullname);
+            SAFE_FREE_STR(item->contact->gov_id);
+            SAFE_FREE_STR(item->contact->hobbies);
+            SAFE_FREE_STR(item->contact->home_address);
+            SAFE_FREE_STR(item->contact->home_city);
+            SAFE_FREE_STR(item->contact->home_country);
+            SAFE_FREE_STR(item->contact->home_fax);
+            SAFE_FREE_STR(item->contact->home_po_box);
+            SAFE_FREE_STR(item->contact->home_phone);
+            SAFE_FREE_STR(item->contact->home_phone2);
+            SAFE_FREE_STR(item->contact->home_postal_code);
+            SAFE_FREE_STR(item->contact->home_state);
+            SAFE_FREE_STR(item->contact->home_street);
+            SAFE_FREE_STR(item->contact->initials);
+            SAFE_FREE_STR(item->contact->isdn_phone);
+            SAFE_FREE_STR(item->contact->job_title);
+            SAFE_FREE_STR(item->contact->keyword);
+            SAFE_FREE_STR(item->contact->language);
+            SAFE_FREE_STR(item->contact->location);
+            SAFE_FREE_STR(item->contact->manager_name);
+            SAFE_FREE_STR(item->contact->middle_name);
+            SAFE_FREE_STR(item->contact->mileage);
+            SAFE_FREE_STR(item->contact->mobile_phone);
+            SAFE_FREE_STR(item->contact->nickname);
+            SAFE_FREE_STR(item->contact->office_loc);
+            SAFE_FREE_STR(item->contact->common_name);
+            SAFE_FREE_STR(item->contact->org_id);
+            SAFE_FREE_STR(item->contact->other_address);
+            SAFE_FREE_STR(item->contact->other_city);
+            SAFE_FREE_STR(item->contact->other_country);
+            SAFE_FREE_STR(item->contact->other_phone);
+            SAFE_FREE_STR(item->contact->other_po_box);
+            SAFE_FREE_STR(item->contact->other_postal_code);
+            SAFE_FREE_STR(item->contact->other_state);
+            SAFE_FREE_STR(item->contact->other_street);
+            SAFE_FREE_STR(item->contact->pager_phone);
+            SAFE_FREE_STR(item->contact->personal_homepage);
+            SAFE_FREE_STR(item->contact->pref_name);
+            SAFE_FREE_STR(item->contact->primary_fax);
+            SAFE_FREE_STR(item->contact->primary_phone);
+            SAFE_FREE_STR(item->contact->profession);
+            SAFE_FREE_STR(item->contact->radio_phone);
+            SAFE_FREE_STR(item->contact->spouse_name);
+            SAFE_FREE_STR(item->contact->suffix);
+            SAFE_FREE_STR(item->contact->surname);
+            SAFE_FREE_STR(item->contact->telex);
+            SAFE_FREE_STR(item->contact->transmittable_display_name);
+            SAFE_FREE_STR(item->contact->ttytdd_phone);
             SAFE_FREE(item->contact->wedding_anniversary);
-            SAFE_FREE(item->contact->work_address_street);
-            SAFE_FREE(item->contact->work_address_city);
-            SAFE_FREE(item->contact->work_address_state);
-            SAFE_FREE(item->contact->work_address_postalcode);
-            SAFE_FREE(item->contact->work_address_country);
-            SAFE_FREE(item->contact->work_address_postofficebox);
+            SAFE_FREE_STR(item->contact->work_address_street);
+            SAFE_FREE_STR(item->contact->work_address_city);
+            SAFE_FREE_STR(item->contact->work_address_state);
+            SAFE_FREE_STR(item->contact->work_address_postalcode);
+            SAFE_FREE_STR(item->contact->work_address_country);
+            SAFE_FREE_STR(item->contact->work_address_postofficebox);
             free(item->contact);
         }
 
@@ -4001,28 +3461,30 @@
         if (item->journal) {
             SAFE_FREE(item->journal->end);
             SAFE_FREE(item->journal->start);
-            SAFE_FREE(item->journal->type);
+            SAFE_FREE_STR(item->journal->type);
             free(item->journal);
         }
         if (item->appointment) {
-            SAFE_FREE(item->appointment->location);
+            SAFE_FREE_STR(item->appointment->location);
             SAFE_FREE(item->appointment->reminder);
-            SAFE_FREE(item->appointment->alarm_filename);
+            SAFE_FREE_STR(item->appointment->alarm_filename);
             SAFE_FREE(item->appointment->start);
             SAFE_FREE(item->appointment->end);
-            SAFE_FREE(item->appointment->timezonestring);
-            SAFE_FREE(item->appointment->recurrence);
+            SAFE_FREE_STR(item->appointment->timezonestring);
+            SAFE_FREE_STR(item->appointment->recurrence);
             SAFE_FREE(item->appointment->recurrence_start);
             SAFE_FREE(item->appointment->recurrence_end);
             free(item->appointment);
         }
         SAFE_FREE(item->ascii_type);
-        SAFE_FREE(item->body_charset);
-        SAFE_FREE(item->comment);
+        SAFE_FREE_STR(item->body_charset);
+        SAFE_FREE_STR(item->body);
+        SAFE_FREE_STR(item->subject);
+        SAFE_FREE_STR(item->comment);
         SAFE_FREE(item->create_date);
-        SAFE_FREE(item->file_as);
+        SAFE_FREE_STR(item->file_as);
         SAFE_FREE(item->modify_date);
-        SAFE_FREE(item->outlook_version);
+        SAFE_FREE_STR(item->outlook_version);
         SAFE_FREE(item->record_key);
         free(item);
     }
@@ -4787,3 +4249,95 @@
 }
 
 
+/** Convert a code page integer into a string suitable for iconv
+ *
+ *  @param cp the code page integer used in the pst file
+ *  @return pointer to a static buffer holding the string representation of the
+ *          equivalent iconv character set
+ */
+const char* codepage(int cp) {
+    static char buffer[20];
+    switch (cp) {
+        case   932 : return "iso-2022-jp";
+        case   936 : return "gb2313";
+        case   950 : return "big5";
+        case 20127 : return "us-ascii";
+        case 20269 : return "iso-6937";
+        case 20865 : return "iso-8859-15";
+        case 20866 : return "koi8-r";
+        case 21866 : return "koi8-u";
+        case 28591 : return "iso-8859-1";
+        case 28592 : return "iso-8859-2";
+        case 28595 : return "iso-8859-5";
+        case 28596 : return "iso-8859-6";
+        case 28597 : return "iso-8859-7";
+        case 28598 : return "iso-8859-8";
+        case 28599 : return "iso-8859-9";
+        case 50220 : return "iso-2022-jp";
+        case 50221 : return "csiso2022jp";
+        case 51932 : return "euc-jp";
+        case 51949 : return "euc-kr";
+        case 65000 : return "utf-7";
+        case 65001 : return "utf-8";
+        default :
+            snprintf(buffer, sizeof(buffer), "windows-%d", cp);
+            return buffer;
+    }
+    return NULL;
+}
+
+
+/** get the default character set for this item
+ *  @param item   pointer to the mapi item of interest
+ *  @return default character set
+ */
+const char*    pst_default_charset(pst_item *item)
+{
+    return (item->body_charset.str) ? item->body_charset.str :
+           (item->message_codepage) ? codepage(item->message_codepage) :
+           (item->internet_cpid)    ? codepage(item->internet_cpid) :
+           "utf-8";
+}
+
+
+/** Convert str to utf8 if possible. Null strings are preserved
+ *
+ *  @param item  pointer to the mapi item of interest
+ *  &param str   pointer to the mapi string of interest
+ */
+void pst_convert_utf8_null(pst_item *item, pst_string *str)
+{
+    if (!str->str) return;
+    pst_convert_utf8(item, str);
+}
+
+
+/** Convert str to utf8 if possible. Null strings are converted into empty strings.
+ *
+ *  @param item  pointer to the mapi item of interest
+ *  &param str   pointer to the mapi string of interest
+ */
+void pst_convert_utf8(pst_item *item, pst_string *str)
+{
+    if (str->is_utf8) return;
+    if (!str->str) {
+        str->str = strdup("");
+        return;
+    }
+    DEBUG_ENT("pst_convert_utf8");
+    const char *charset = pst_default_charset(item);
+    if (!strcasecmp("utf-8", charset)) return;  // already utf8
+    vbuf *newer = vballoc(2);
+    size_t rc = vb_8bit2utf8(newer, str->str, strlen(str->str) + 1, charset);
+    if (rc == (size_t)-1) {
+        free(newer->b);
+        DEBUG_EMAIL(("Failed to convert %s to utf-8 - %s\n", charset, str->str));
+    }
+    else {
+        free(str->str);
+        str->str = newer->b;
+        str->is_utf8 = 1;
+    }
+    free(newer);
+    DEBUG_RET();
+}
--- a/src/libpst.h	Thu Mar 05 08:23:32 2009 -0800
+++ b/src/libpst.h	Sun Mar 08 14:35:26 2009 -0700
@@ -166,23 +166,19 @@
 } pst_desc_ll;
 
 
-typedef struct pst_item_email_subject {
-    int     off1;
-    int     off2;
-    char   *subj;
-} pst_item_email_subject;
+typedef struct pst_string {
+    int     is_utf8;    // 1 = true, 0 = false
+    char   *str;        // either utf8 or some sbcs
+} pst_string;
 
 
 typedef struct pst_item_email {
     FILETIME   *arrival_date;
     int         autoforward;            // 1 = true, 0 = not set, -1 = false
-    char       *body;
-    int32_t     body_was_unicode;       // 1 = true, 0 = false
-    char       *cc_address;
-    char       *bcc_address;
-    char       *common_name;
+    pst_string  cc_address;
+    pst_string  bcc_address;
     int32_t     conv_index;
-    int         conversion_prohib;      // 1 = true, 0 = false
+    int         conversion_prohibited;  // 1 = true, 0 = false
     int         delete_after_submit;    // 1 = true, 0 = false
     int         delivery_report;        // 1 = true, 0 = false
     char       *encrypted_body;
@@ -190,59 +186,56 @@
     char       *encrypted_htmlbody;
     size_t      encrypted_htmlbody_size;
     int32_t     flag;
-    char       *header;
-    char       *htmlbody;
-    int32_t     htmlbody_was_unicode;   // 1 = true, 0 = false
+    pst_string  header;
+    pst_string  htmlbody;
     int32_t     importance;
-    char       *in_reply_to;
+    pst_string  in_reply_to;
     int         message_cc_me;          // 1 = true, 0 = false
     int         message_recip_me;       // 1 = true, 0 = false
     int         message_to_me;          // 1 = true, 0 = false
-    char       *messageid;
+    pst_string  messageid;
     int32_t     orig_sensitivity;
-    char       *original_bcc;
-    char       *original_cc;
-    char       *original_to;
-    char       *outlook_recipient;
-    char       *outlook_recipient_name;
-    char       *outlook_recipient2;
-    char       *outlook_sender;
-    char       *outlook_sender_name;
-    char       *outlook_sender2;
+    pst_string  original_bcc;
+    pst_string  original_cc;
+    pst_string  original_to;
+    pst_string  outlook_recipient;
+    pst_string  outlook_recipient_name;
+    pst_string  outlook_recipient2;
+    pst_string  outlook_sender;
+    pst_string  outlook_sender_name;
+    pst_string  outlook_sender2;
     int32_t     priority;
-    char       *proc_subject;
+    pst_string  processed_subject;
     int         read_receipt;           // 1 = true, 0 = false
-    char       *recip_access;
-    char       *recip_address;
-    char       *recip2_access;
-    char       *recip2_address;
+    pst_string  recip_access;
+    pst_string  recip_address;
+    pst_string  recip2_access;
+    pst_string  recip2_address;
     int         reply_requested;        // 1 = true, 0 = false
-    char       *reply_to;
-    char       *return_path_address;
+    pst_string  reply_to;
+    pst_string  return_path_address;
     int32_t     rtf_body_char_count;
     int32_t     rtf_body_crc;
-    char       *rtf_body_tag;
+    pst_string  rtf_body_tag;
     char       *rtf_compressed;
     uint32_t    rtf_compressed_size;
     int         rtf_in_sync;            // 1 = true, 0 = doesn't exist, -1 = false
     int32_t     rtf_ws_prefix_count;
     int32_t     rtf_ws_trailing_count;
-    char       *sender_access;
-    char       *sender_address;
-    char       *sender2_access;
-    char       *sender2_address;
+    pst_string  sender_access;
+    pst_string  sender_address;
+    pst_string  sender2_access;
+    pst_string  sender2_address;
     int32_t     sensitivity;
-    FILETIME   *sent_date;
-    pst_entryid            *sentmail_folder;
-    char                   *sentto_address;
-    pst_item_email_subject *subject;
+    FILETIME    *sent_date;
+    pst_entryid *sentmail_folder;
+    pst_string  sentto_address;
     // delivery report fields
-    char       *report_text;
-    int32_t     report_was_unicode;
+    pst_string  report_text;
     FILETIME   *report_time;
     int32_t     ndr_reason_code;
     int32_t     ndr_diag_code;
-    char       *supplementary_info;
+    pst_string  supplementary_info;
     int32_t     ndr_status_code;
 } pst_item_email;
 
@@ -270,154 +263,155 @@
 
 
 typedef struct pst_item_contact {
-    char *access_method;
-    char *account_name;
-    char *address1;
-    char *address1a;
-    char *address1_desc;
-    char *address1_transport;
-    char *address2;
-    char *address2a;
-    char *address2_desc;
-    char *address2_transport;
-    char *address3;
-    char *address3a;
-    char *address3_desc;
-    char *address3_transport;
-    char *assistant_name;
-    char *assistant_phone;
-    char *billing_information;
-    FILETIME *birthday;
-    char *business_address;             // 0x801b
-    char *business_city;
-    char *business_country;
-    char *business_fax;
-    char *business_homepage;
-    char *business_phone;
-    char *business_phone2;
-    char *business_po_box;
-    char *business_postal_code;
-    char *business_state;
-    char *business_street;
-    char *callback_phone;
-    char *car_phone;
-    char *company_main_phone;
-    char *company_name;
-    char *computer_name;
-    char *customer_id;
-    char *def_postal_address;
-    char *department;
-    char *display_name_prefix;
-    char *first_name;
-    char *followup;
-    char *free_busy_address;
-    char *ftp_site;
-    char *fullname;
-    int16_t  gender;
-    char *gov_id;
-    char *hobbies;
-    char *home_address;                 // 0x801a
-    char *home_city;
-    char *home_country;
-    char *home_fax;
-    char *home_phone;
-    char *home_phone2;
-    char *home_po_box;
-    char *home_postal_code;
-    char *home_state;
-    char *home_street;
-    char *initials;
-    char *isdn_phone;
-    char *job_title;
-    char *keyword;
-    char *language;
-    char *location;
-    int   mail_permission;              // 1 = true, 0 = false
-    char *manager_name;
-    char *middle_name;
-    char *mileage;
-    char *mobile_phone;
-    char *nickname;
-    char *office_loc;
-    char *org_id;
-    char *other_address;                // 0x801c
-    char *other_city;
-    char *other_country;
-    char *other_phone;
-    char *other_po_box;
-    char *other_postal_code;
-    char *other_state;
-    char *other_street;
-    char *pager_phone;
-    char *personal_homepage;
-    char *pref_name;
-    char *primary_fax;
-    char *primary_phone;
-    char *profession;
-    char *radio_phone;
-    int   rich_text;                    // 1 = true, 0 = false
-    char *spouse_name;
-    char *suffix;
-    char *surname;
-    char *telex;
-    char *transmittable_display_name;
-    char *ttytdd_phone;
-    FILETIME *wedding_anniversary;
-    char *work_address_street;          // 0x8045
-    char *work_address_city;            // 0x8046
-    char *work_address_state;           // 0x8047
-    char *work_address_postalcode;      // 0x8048
-    char *work_address_country;         // 0x8049
-    char *work_address_postofficebox;   // 0x804a
+    pst_string  access_method;
+    pst_string  account_name;
+    pst_string  address1;
+    pst_string  address1a;
+    pst_string  address1_desc;
+    pst_string  address1_transport;
+    pst_string  address2;
+    pst_string  address2a;
+    pst_string  address2_desc;
+    pst_string  address2_transport;
+    pst_string  address3;
+    pst_string  address3a;
+    pst_string  address3_desc;
+    pst_string  address3_transport;
+    pst_string  assistant_name;
+    pst_string  assistant_phone;
+    pst_string  billing_information;
+    FILETIME   *birthday;
+    pst_string  business_address;               // 0x801b
+    pst_string  business_city;
+    pst_string  business_country;
+    pst_string  business_fax;
+    pst_string  business_homepage;
+    pst_string  business_phone;
+    pst_string  business_phone2;
+    pst_string  business_po_box;
+    pst_string  business_postal_code;
+    pst_string  business_state;
+    pst_string  business_street;
+    pst_string  callback_phone;
+    pst_string  car_phone;
+    pst_string  company_main_phone;
+    pst_string  company_name;
+    pst_string  computer_name;
+    pst_string  customer_id;
+    pst_string  def_postal_address;
+    pst_string  department;
+    pst_string  display_name_prefix;
+    pst_string  first_name;
+    pst_string  followup;
+    pst_string  free_busy_address;
+    pst_string  ftp_site;
+    pst_string  fullname;
+    int16_t     gender;
+    pst_string  gov_id;
+    pst_string  hobbies;
+    pst_string  home_address;                   // 0x801a
+    pst_string  home_city;
+    pst_string  home_country;
+    pst_string  home_fax;
+    pst_string  home_phone;
+    pst_string  home_phone2;
+    pst_string  home_po_box;
+    pst_string  home_postal_code;
+    pst_string  home_state;
+    pst_string  home_street;
+    pst_string  initials;
+    pst_string  isdn_phone;
+    pst_string  job_title;
+    pst_string  keyword;
+    pst_string  language;
+    pst_string  location;
+    int         mail_permission;                // 1 = true, 0 = false
+    pst_string  manager_name;
+    pst_string  middle_name;
+    pst_string  mileage;
+    pst_string  mobile_phone;
+    pst_string  nickname;
+    pst_string  office_loc;
+    pst_string  common_name;
+    pst_string  org_id;
+    pst_string  other_address;                  // 0x801c
+    pst_string  other_city;
+    pst_string  other_country;
+    pst_string  other_phone;
+    pst_string  other_po_box;
+    pst_string  other_postal_code;
+    pst_string  other_state;
+    pst_string  other_street;
+    pst_string  pager_phone;
+    pst_string  personal_homepage;
+    pst_string  pref_name;
+    pst_string  primary_fax;
+    pst_string  primary_phone;
+    pst_string  profession;
+    pst_string  radio_phone;
+    int         rich_text;                      // 1 = true, 0 = false
+    pst_string  spouse_name;
+    pst_string  suffix;
+    pst_string  surname;
+    pst_string  telex;
+    pst_string  transmittable_display_name;
+    pst_string  ttytdd_phone;
+    FILETIME   *wedding_anniversary;
+    pst_string  work_address_street;            // 0x8045
+    pst_string  work_address_city;              // 0x8046
+    pst_string  work_address_state;             // 0x8047
+    pst_string  work_address_postalcode;        // 0x8048
+    pst_string  work_address_country;           // 0x8049
+    pst_string  work_address_postofficebox;     // 0x804a
 } pst_item_contact;
 
 
 typedef struct pst_item_attach {
-    char *filename1;
-    char *filename2;
-    char *mimetype;
-    char *data;
-    size_t   size;
-    uint64_t id2_val;
-    uint64_t id_val;            // calculated from id2_val during creation of record
-    pst_id2_ll *id2_head;    // deep copy from child
-    int32_t  method;
-    int32_t  position;
-    int32_t  sequence;
+    pst_string  filename1;
+    pst_string  filename2;
+    pst_string  mimetype;
+    char       *data;
+    size_t      size;
+    uint64_t    id2_val;
+    uint64_t    id_val;     // calculated from id2_val during creation of record
+    pst_id2_ll *id2_head;   // deep copy from child
+    int32_t     method;
+    int32_t     position;
+    int32_t     sequence;
     struct pst_item_attach *next;
 } pst_item_attach;
 
 
 typedef struct pst_item_extra_field {
-    char *field_name;
-    char *value;
+    char   *field_name;
+    char   *value;
     struct pst_item_extra_field *next;
 } pst_item_extra_field;
 
 
 typedef struct pst_item_journal {
-    FILETIME *end;
-    FILETIME *start;
-    char *type;
+    FILETIME   *end;
+    FILETIME   *start;
+    pst_string  type;
 } pst_item_journal;
 
 
 typedef struct pst_item_appointment {
-    FILETIME *end;
-    char     *location;
-    int       alarm;                // 1 = true, 0 = false
-    FILETIME *reminder;
-    int32_t   alarm_minutes;
-    char     *alarm_filename;
-    FILETIME *start;
-    char     *timezonestring;
-    int32_t   showas;
-    int32_t   label;
-    int       all_day;              // 1 = true, 0 = false
-    char     *recurrence;
-    int32_t   recurrence_type;
-    FILETIME *recurrence_start;
-    FILETIME *recurrence_end;
+    FILETIME   *end;
+    pst_string  location;
+    int         alarm;              // 1 = true, 0 = false
+    FILETIME   *reminder;
+    int32_t     alarm_minutes;
+    pst_string  alarm_filename;
+    FILETIME   *start;
+    pst_string  timezonestring;
+    int32_t     showas;
+    int32_t     label;
+    int         all_day;            // 1 = true, 0 = false
+    pst_string  recurrence;
+    int32_t     recurrence_type;
+    FILETIME   *recurrence_start;
+    FILETIME   *recurrence_end;
 } pst_item_appointment;
 
 
@@ -432,14 +426,16 @@
     struct pst_item_appointment   *appointment;     // data referring to a calendar entry
     int         type;
     char       *ascii_type;
-    char       *file_as;
-    char       *comment;
-    char       *body_charset;           // null if not specified
+    pst_string  file_as;
+    pst_string  comment;
+    pst_string  body_charset;           // null if not specified
+    pst_string  body;                   // email, journal
+    pst_string  subject;                // email, journal
     int32_t     internet_cpid;
     int32_t     message_codepage;
     int32_t     message_size;
-    char       *outlook_version;
-    char       *record_key; // probably 16 bytes long.
+    pst_string  outlook_version;
+    char       *record_key;             // probably 16 bytes long.
     size_t      record_key_size;
     int         response_requested;     // 1 = true, 0 = false
     FILETIME   *create_date;
@@ -589,6 +585,11 @@
 void           pst_printIDptr(pst_file* pf);
 void           pst_printID2ptr(pst_id2_ll *ptr);
 
+const char*    pst_codepage(int cp);
+const char*    pst_default_charset(pst_item *item);
+void           pst_convert_utf8_null(pst_item *item, pst_string *str);
+void           pst_convert_utf8(pst_item *item, pst_string *str);
+
 
 // switch from maximal packing back to default packing
 // undo the packing from the beginning of this file
--- a/src/libstrfunc.c	Thu Mar 05 08:23:32 2009 -0800
+++ b/src/libstrfunc.c	Sun Mar 08 14:35:26 2009 -0700
@@ -63,29 +63,3 @@
 };
 
 
-void hexdump(char *hbuf, int start, int stop, int ascii) /* {{{ HexDump all or a part of some buffer */
-{
-    char c;
-    int diff,i;
-
-    while (start < stop ) {
-        diff = stop - start;
-        if (diff > 16) diff = 16;
-
-        fprintf(stderr, ":%08X  ",start);
-
-        for (i = 0; i < diff; i++) {
-            if( 8 == i ) fprintf( stderr, " " );
-            fprintf(stderr, "%02X ",(unsigned char)*(hbuf+start+i));
-        }
-        if (ascii) {
-            for (i = diff; i < 16; i++) fprintf(stderr, "   ");
-            for (i = 0; i < diff; i++) {
-                c = *(hbuf+start+i);
-                fprintf(stderr, "%c", isprint(c) ? c : '.');
-            }
-        }
-        fprintf(stderr, "\n");
-        start += 16;
-    }
-}
--- a/src/lspst.c	Thu Mar 05 08:23:32 2009 -0800
+++ b/src/lspst.c	Sun Mar 08 14:35:26 2009 -0700
@@ -28,12 +28,13 @@
 
 void create_enter_dir(struct file_ll* f, pst_item *item)
 {
+    pst_convert_utf8(item, &item->file_as);
     f->email_count  = 0;
     f->skip_count   = 0;
     f->type         = item->type;
     f->stored_count = (item->folder) ? item->folder->email_count : 0;
-    f->dname        = (char*) xmalloc(strlen(item->file_as)+1);
-    strcpy(f->dname, item->file_as);
+    f->dname        = (char*) xmalloc(strlen(item->file_as.str)+1);
+    strcpy(f->dname, item->file_as.str);
 }
 
 
@@ -70,7 +71,8 @@
 
                 if (item->folder && d_ptr->child) {
                     // if this is a folder, we want to recurse into it
-                    printf("Folder \"%s\"\n", item->file_as);
+                    pst_convert_utf8(item, &item->file_as);
+                    printf("Folder \"%s\"\n", item->file_as.str);
                     process(item, d_ptr->child);
 
                 } else if (item->contact && (item->type == PST_TYPE_CONTACT)) {
@@ -79,8 +81,8 @@
                         DEBUG_MAIN(("main: I have a contact, but the folder isn't a contacts folder. Processing anyway\n"));
                     }
                     printf("Contact");
-                    if (item->contact->fullname)
-                        printf("\t%s", pst_rfc2426_escape(item->contact->fullname));
+                    if (item->contact->fullname.str)
+                        printf("\t%s", pst_rfc2426_escape(item->contact->fullname.str));
                     printf("\n");
 
                 } else if (item->email && (item->type == PST_TYPE_NOTE || item->type == PST_TYPE_REPORT || item->type == PST_TYPE_OTHER)) {
@@ -89,10 +91,10 @@
                         DEBUG_MAIN(("main: I have an email, but the folder isn't an email folder. Processing anyway\n"));
                     }
                     printf("Email");
-                    if (item->email->outlook_sender_name)
-                        printf("\tFrom: %s", item->email->outlook_sender_name);
-                    if (item->email->subject && item->email->subject->subj)
-                        printf("\tSubject: %s", item->email->subject->subj);
+                    if (item->email->outlook_sender_name.str)
+                        printf("\tFrom: %s", item->email->outlook_sender_name.str);
+                    if (item->subject.str)
+                        printf("\tSubject: %s", item->subject.str);
                     printf("\n");
 
                 } else if (item->journal && (item->type == PST_TYPE_JOURNAL)) {
@@ -100,8 +102,8 @@
                     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->email && item->email->subject && item->email->subject->subj)
-                        printf("Journal\t%s\n", pst_rfc2426_escape(item->email->subject->subj));
+                    if (item->subject.str)
+                        printf("Journal\t%s\n", pst_rfc2426_escape(item->subject.str));
 
                 } else if (item->appointment && (item->type == PST_TYPE_APPOINTMENT)) {
                     // Process Calendar Appointment item
@@ -110,8 +112,8 @@
                         DEBUG_MAIN(("main: I have an appointment, but folder isn't specified as an appointment type. Processing...\n"));
                     }
                     printf("Appointment");
-                    if (item->email && item->email->subject)
-                        printf("\tSUMMARY: %s", pst_rfc2426_escape(item->email->subject->subj));
+                    if (item->subject.str)
+                        printf("\tSUMMARY: %s", pst_rfc2426_escape(item->subject.str));
                     if (item->appointment->start)
                         printf("\tSTART: %s", pst_rfc2445_datetime_format(item->appointment->start));
                     if (item->appointment->end)
@@ -222,7 +224,7 @@
     }
 
     // default the file_as to the same as the main filename if it doesn't exist
-    if (!item->file_as) {
+    if (!item->file_as.str) {
         if (!(temp = strrchr(argv[1], '/')))
             if (!(temp = strrchr(argv[1], '\\')))
                 temp = argv[1];
@@ -230,10 +232,11 @@
                 temp++; // get past the "\\"
         else
             temp++; // get past the "/"
-        item->file_as = (char*)xmalloc(strlen(temp)+1);
-        strcpy(item->file_as, temp);
+        item->file_as.str = (char*)xmalloc(strlen(temp)+1);
+        strcpy(item->file_as.str, temp);
+        item->file_as.is_utf8 = 1;
     }
-    fprintf(stderr, "item->file_as = '%s'.\n", item->file_as);
+    WARN(("item->file_as = '%s'.\n", item->file_as.str));
 
     d_ptr = pst_getTopOfFolders(&pstfile, item);
     if (!d_ptr) DIE(("Top of folders record not found. Cannot continue\n"));
@@ -262,48 +265,3 @@
 }
 
 
-void debug_print(char *fmt, ...) {
-    // shamlessly stolen from minprintf() in K&R pg. 156
-    va_list ap;
-    char *p, *sval;
-    void *pval;
-    int ival;
-    double dval;
-    FILE *fp = stderr;
-
-    va_start(ap, fmt);
-    for(p = fmt; *p; p++) {
-        if (*p != '%') {
-            fputc(*p, fp);
-            continue;
-        }
-        switch (tolower(*++p)) {
-            case 'd': case 'i':
-                ival = va_arg(ap, int);
-                fprintf(fp, "%d", ival);
-                break;
-            case 'f':
-                dval = va_arg(ap, double);
-                fprintf(fp, "%f", dval);
-                break;
-            case 's':
-                for (sval = va_arg(ap, char *); *sval; ++sval)
-                    fputc(*sval, fp);
-                break;
-            case 'p':
-                pval = va_arg(ap, void *);
-                fprintf(fp, "%p", pval);
-                break;
-            case 'x':
-                ival = va_arg(ap, int);
-                fprintf(fp, "%#010x", ival);
-                break;
-            default:
-                fputc(*p, fp);
-                break;
-        }
-    }
-    va_end(ap);
-}
-
-
--- a/src/pst2dii.cpp.in	Thu Mar 05 08:23:32 2009 -0800
+++ b/src/pst2dii.cpp.in	Sun Mar 08 14:35:26 2009 -0700
@@ -175,8 +175,8 @@
 
     // If there is a long filename (filename2) use that, otherwise
     // use the 8.3 filename (filename1)
-    char *attach_filename = (current_attach->filename2) ? current_attach->filename2
-                                                        : current_attach->filename1;
+    char *attach_filename = (current_attach->filename2.str) ? current_attach->filename2.str
+                                                            : current_attach->filename1.str;
     DEBUG_ENT("write_separate_attachment");
     check_filename(fname);
     const char* f_name = fname.c_str();
@@ -445,17 +445,17 @@
 {
     DEBUG_ENT("write_normal_email");
     char *soh = NULL;  // real start of headers.
-    if (item->email->header) {
+    if (item->email->header.str) {
         // some of the headers we get from the file are not properly defined.
         // they can contain some email stuff too. We will cut off the header
         // when we see a \n\n or \r\n\r\n
-        removeCR(item->email->header);
-        char *temp = strstr(item->email->header, "\n\n");
+        removeCR(item->email->header.str);
+        char *temp = strstr(item->email->header.str, "\n\n");
         if (temp) {
             DEBUG_EMAIL(("Found body text in header\n"));
             temp[1] = '\0'; // stop after first \n
         }
-        soh = skip_header_prologue(item->email->header);
+        soh = skip_header_prologue(item->email->header.str);
     }
 
     char folder_line[LINE_SIZE];
@@ -471,13 +471,13 @@
     string myto   = extract_header(soh, "To");
     string mycc   = extract_header(soh, "Cc");
     string mybcc  = extract_header(soh, "Bcc");
-    if (myfrom.empty()) write_simple("FROM", item->email->outlook_sender_name, item->email->sender_address);
+    if (myfrom.empty()) write_simple("FROM", item->email->outlook_sender_name.str, item->email->sender_address.str);
     else                write_simple("FROM", myfrom);
-    if (myto.empty())   write_simple("TO",   item->email->sentto_address,      item->email->recip_address);
+    if (myto.empty())   write_simple("TO",   item->email->sentto_address.str,      item->email->recip_address.str);
     else                write_simple("TO", myto);
-    if (mycc.empty())   write_simple("CC",   item->email->cc_address);
+    if (mycc.empty())   write_simple("CC",   item->email->cc_address.str);
     else                write_simple("CC", mycc);
-    if (mybcc.empty())  write_simple("BCC",  item->email->bcc_address);
+    if (mybcc.empty())  write_simple("BCC",  item->email->bcc_address.str);
     else                write_simple("BCC", mybcc);
     if (item->email->sent_date) {
         time_t t = fileTimeToUnixTime(item->email->sent_date, NULL);
@@ -495,10 +495,10 @@
         strftime(c_time, C_TIME_SIZE, "%T+0000", gmtime(&t));
         write_simple("TIMERCVD", c_time);
     }
-    if (item->email->subject) {
-        write_simple("SUBJECT", item->email->subject->subj);
+    if (item->subject.str) {
+        write_simple("SUBJECT", item->subject.str);
     }
-    write_simple("MSGID", item->email->messageid);
+    write_simple("MSGID", item->email->messageid.str);
     if (item->email->flag) {
         write_simple("READ", (item->email->flag & 1) ? "Y" : "N");
     }
@@ -506,8 +506,8 @@
     DEBUG_EMAIL(("About to print Header\n"));
     fprintf(dii_file, "@HEADER\n");
 
-    if (item && item->email && item->email->subject && item->email->subject->subj) {
-        DEBUG_EMAIL(("item->email->subject->subj = %s\n", item->email->subject->subj));
+    if (item && item->subject.str) {
+        DEBUG_EMAIL(("item->subject = %s\n", item->subject.str));
     }
 
     if (soh) {
@@ -521,23 +521,23 @@
 
     } else {
         //make up our own headers
-        const char *temp = item->email->outlook_sender;
+        const char *temp = item->email->outlook_sender.str;
         if (!temp) temp = "";
-        snprintf(line, sizeof(line), "From: \"%s\" <%s>\n", item->email->outlook_sender_name, temp);
+        snprintf(line, sizeof(line), "From: \"%s\" <%s>\n", item->email->outlook_sender_name.str, temp);
         print_pdf(line);
 
-        if (item->email->subject) {
-            snprintf(line, sizeof(line), "Subject: %s\n", item->email->subject->subj);
+        if (item->subject.str) {
+            snprintf(line, sizeof(line), "Subject: %s\n", item->subject.str);
         } else {
             snprintf(line, sizeof(line), "Subject: \n");
         }
         print_pdf(line);
 
-        snprintf(line, sizeof(line), "To: %s\n", item->email->sentto_address);
+        snprintf(line, sizeof(line), "To: %s\n", item->email->sentto_address.str);
         print_pdf(line);
 
-        if (item->email->cc_address) {
-            snprintf(line, sizeof(line), "Cc: %s\n", item->email->cc_address);
+        if (item->email->cc_address.str) {
+            snprintf(line, sizeof(line), "Cc: %s\n", item->email->cc_address.str);
             print_pdf(line);
         }
 
@@ -555,12 +555,12 @@
 
     DEBUG_EMAIL(("About to print Body\n"));
     fprintf(dii_file, "@EMAIL-BODY\n");
-    if (item->email->body) {
-        removeCR(item->email->body);
-        print_pdf(item->email->body);
-    } else if (item->email->htmlbody) {
-        removeCR(item->email->htmlbody);
-        print_pdf(item->email->htmlbody);
+    if (item->body.str) {
+        removeCR(item->body.str);
+        print_pdf(item->body.str);
+    } else if (item->email->htmlbody.str) {
+        removeCR(item->email->htmlbody.str);
+        print_pdf(item->email->htmlbody.str);
     } else if (item->email->encrypted_body || item->email->encrypted_htmlbody) {
         char ln[LINE_SIZE];
         snprintf(ln, sizeof(ln), "%s", "The body of this email is encrypted. This isn't supported yet, but the body is now an attachment\n");
@@ -591,7 +591,7 @@
     f.skip_count   = 0;
     f.type         = item->type;
     f.stored_count = (item->folder) ? item->folder->email_count : 0;
-    f.name         = ((parent) ? parent->name + "/" : "") + string(item->file_as);
+    f.name         = ((parent) ? parent->name + "/" : "") + string(item->file_as.str);
 }
 
 
--- a/src/pst2ldif.cpp	Thu Mar 05 08:23:32 2009 -0800
+++ b/src/pst2ldif.cpp	Sun Mar 08 14:35:26 2009 -0700
@@ -24,19 +24,19 @@
 void       version(void);
 char       *check_filename(char *fname);
 void        print_ldif_single(const char *attr, const char *value);
-void        print_ldif_address(const char *attr, int nvalues, char *value, ...);
-void        print_ldif_dn(const char *attr, const char *value, const char *base);
-void        print_ldif_multi(const char *dn, const char *value);
-void        print_ldif_two(const char *attr, const char *value1, const char *value2);
+void        print_ldif_single(const char *attr, pst_string value);
+void        print_ldif_address(const char *attr, int nvalues, pst_string value, ...);
+void        print_ldif_dn(const char *attr, pst_string value, const char *base);
+void        print_ldif_multi(const char *dn, pst_string value);
+void        print_ldif_two(const char *attr, pst_string value1, pst_string value2);
 void        print_escaped_dn(const char *value);
-void        build_cn(char *cn, size_t len, int nvalues, char *value, ...);
+void        build_cn(char *cn, size_t len, int nvalues, pst_string value, ...);
 
 char *prog_name;
 pst_file pstfile;
 bool    old_schema            = false;
 char    *ldap_base            = NULL;   // 'o=some.domain.tld,c=US'
 int     ldif_extra_line_count = 0;
-iconv_t cd                    = 0;      // Character set conversion descriptor
 vector<string> ldap_class;              // 'newPerson' or 'inetOrgPerson'
 vector<string> ldif_extra_line;         // 'o: myorg'
 
@@ -108,21 +108,64 @@
 
 static void process(pst_desc_ll *d_ptr);
 static void process(pst_desc_ll *d_ptr) {
+    DEBUG_ENT("process");
     pst_item *item = NULL;
     while (d_ptr) {
         if (d_ptr->desc) {
             item = pst_parse_item(&pstfile, d_ptr, NULL);
             DEBUG_INFO(("item pointer is %p\n", item));
             if (item) {
-                if (item->folder && d_ptr->child && strcasecmp(item->file_as, "Deleted Items")) {
+                if (item->folder && d_ptr->child && item->file_as.str && strcasecmp(item->file_as.str, "Deleted Items")) {
                     //if this is a non-empty folder other than deleted items, we want to recurse into it
-                    fprintf(stderr, "entering folder %s\n", item->file_as);
+                    fprintf(stderr, "entering folder %s\n", item->file_as.str);
                     process(d_ptr->child);
 
                 } else if (item->contact && (item->type == PST_TYPE_CONTACT)) {
                     // deal with a contact
                     char cn[1000];
 
+                    // convert everything to utf8
+                    pst_convert_utf8_null(item, &item->contact->display_name_prefix);
+                    pst_convert_utf8_null(item, &item->contact->first_name);
+                    pst_convert_utf8_null(item, &item->contact->surname);
+                    pst_convert_utf8_null(item, &item->contact->suffix);
+                    pst_convert_utf8_null(item, &item->contact->company_name);
+                    pst_convert_utf8_null(item, &item->contact->job_title);
+                    pst_convert_utf8_null(item, &item->contact->address1);
+                    pst_convert_utf8_null(item, &item->contact->address2);
+                    pst_convert_utf8_null(item, &item->contact->address3);
+                    pst_convert_utf8_null(item, &item->contact->address1a);
+                    pst_convert_utf8_null(item, &item->contact->address2a);
+                    pst_convert_utf8_null(item, &item->contact->address3a);
+                    pst_convert_utf8_null(item, &item->contact->business_address);
+                    pst_convert_utf8_null(item, &item->contact->business_po_box);
+                    pst_convert_utf8_null(item, &item->contact->business_street);
+                    pst_convert_utf8_null(item, &item->contact->business_city);
+                    pst_convert_utf8_null(item, &item->contact->business_state);
+                    pst_convert_utf8_null(item, &item->contact->business_postal_code);
+                    pst_convert_utf8_null(item, &item->contact->home_address);
+                    pst_convert_utf8_null(item, &item->contact->home_po_box);
+                    pst_convert_utf8_null(item, &item->contact->home_street);
+                    pst_convert_utf8_null(item, &item->contact->home_city);
+                    pst_convert_utf8_null(item, &item->contact->home_state);
+                    pst_convert_utf8_null(item, &item->contact->home_postal_code);
+                    pst_convert_utf8_null(item, &item->contact->other_address);
+                    pst_convert_utf8_null(item, &item->contact->other_po_box);
+                    pst_convert_utf8_null(item, &item->contact->other_street);
+                    pst_convert_utf8_null(item, &item->contact->other_city);
+                    pst_convert_utf8_null(item, &item->contact->other_state);
+                    pst_convert_utf8_null(item, &item->contact->other_postal_code);
+                    pst_convert_utf8_null(item, &item->contact->business_fax);
+                    pst_convert_utf8_null(item, &item->contact->home_fax);
+                    pst_convert_utf8_null(item, &item->contact->business_phone);
+                    pst_convert_utf8_null(item, &item->contact->home_phone);
+                    pst_convert_utf8_null(item, &item->contact->car_phone);
+                    pst_convert_utf8_null(item, &item->contact->mobile_phone);
+                    pst_convert_utf8_null(item, &item->contact->other_phone);
+                    pst_convert_utf8_null(item, &item->contact->business_homepage);
+                    pst_convert_utf8_null(item, &item->contact->personal_homepage);
+                    pst_convert_utf8_null(item, &item->comment);
+
                     build_cn(cn, sizeof(cn), 4,
                         item->contact->display_name_prefix,
                         item->contact->first_name,
@@ -130,93 +173,94 @@
                         item->contact->suffix);
                     if (cn[0] != 0) {
                         // have a valid cn
-                        const char *ucn = unique_string(cn);
+                        pst_string ucn;
+                        ucn.str = (char*)unique_string(cn);
 
                         print_ldif_dn("dn", ucn, ldap_base);
                         print_ldif_single("cn", ucn);
-                        if (item->contact->first_name) {
+                        if (item->contact->first_name.str) {
                             print_ldif_two("givenName",
                                            item->contact->display_name_prefix,
                                            item->contact->first_name);
                         }
-                        if (item->contact->surname) {
+                        if (item->contact->surname.str) {
                             print_ldif_two("sn",
                                            item->contact->surname,
                                            item->contact->suffix);
                         }
-                        else if (item->contact->company_name) {
+                        else if (item->contact->company_name.str) {
                             print_ldif_single("sn", item->contact->company_name);
                         }
                         else
                             print_ldif_single("sn", ucn); // use cn as sn if we cannot find something better
 
                         if (old_schema) {
-                            if (item->contact->job_title)
+                            if (item->contact->job_title.str)
                                 print_ldif_single("personalTitle", item->contact->job_title);
-                            if (item->contact->company_name)
+                            if (item->contact->company_name.str)
                                 print_ldif_single("company", item->contact->company_name);
                         }
                         else {
                             // new schema
-                            if (item->contact->job_title)
+                            if (item->contact->job_title.str)
                                 print_ldif_single("title", item->contact->job_title);
-                            if (item->contact->company_name)
+                            if (item->contact->company_name.str)
                                 print_ldif_single("o", item->contact->company_name);
                         }
-                        if (item->contact->address1  && *item->contact->address1)
+                        if (item->contact->address1.str  && *item->contact->address1.str)
                             print_ldif_single("mail", item->contact->address1);
-                        if (item->contact->address2  && *item->contact->address2)
+                        if (item->contact->address2.str  && *item->contact->address2.str)
                             print_ldif_single("mail", item->contact->address2);
-                        if (item->contact->address3  && *item->contact->address3)
+                        if (item->contact->address3.str  && *item->contact->address3.str)
                             print_ldif_single("mail", item->contact->address3);
-                        if (item->contact->address1a && *item->contact->address1a)
+                        if (item->contact->address1a.str && *item->contact->address1a.str)
                             print_ldif_single("mail", item->contact->address1a);
-                        if (item->contact->address2a && *item->contact->address2a)
+                        if (item->contact->address2a.str && *item->contact->address2a.str)
                             print_ldif_single("mail", item->contact->address2a);
-                        if (item->contact->address3a && *item->contact->address3a)
+                        if (item->contact->address3a.str && *item->contact->address3a.str)
                             print_ldif_single("mail", item->contact->address3a);
 
                         if (old_schema) {
-                            if (item->contact->business_address) {
-                                if (item->contact->business_po_box)
+                            if (item->contact->business_address.str) {
+                                if (item->contact->business_po_box.str)
                                     print_ldif_single("postalAddress", item->contact->business_po_box);
-                                if (item->contact->business_street)
+                                if (item->contact->business_street.str)
                                     print_ldif_multi("postalAddress", item->contact->business_street);
-                                if (item->contact->business_city)
+                                if (item->contact->business_city.str)
                                     print_ldif_single("l", item->contact->business_city);
-                                if (item->contact->business_state)
+                                if (item->contact->business_state.str)
                                     print_ldif_single("st", item->contact->business_state);
-                                if (item->contact->business_postal_code)
+                                if (item->contact->business_postal_code.str)
                                     print_ldif_single("postalCode", item->contact->business_postal_code);
                             }
-                            else if (item->contact->home_address) {
-                                if (item->contact->home_po_box)
+                            else if (item->contact->home_address.str) {
+                                if (item->contact->home_po_box.str)
                                     print_ldif_single("postalAddress", item->contact->home_po_box);
-                                if (item->contact->home_street)
+                                if (item->contact->home_street.str)
                                     print_ldif_multi("postalAddress", item->contact->home_street);
-                                if (item->contact->home_city)
+                                if (item->contact->home_city.str)
                                     print_ldif_single("l", item->contact->home_city);
-                                if (item->contact->home_state)
+                                if (item->contact->home_state.str)
                                     print_ldif_single("st", item->contact->home_state);
-                                if (item->contact->home_postal_code)
+                                if (item->contact->home_postal_code.str)
                                     print_ldif_single("postalCode", item->contact->home_postal_code);
                             }
-                            else if (item->contact->other_address) {
-                                if (item->contact->other_po_box)
+                            else if (item->contact->other_address.str) {
+                                if (item->contact->other_po_box.str)
                                     print_ldif_single("postalAddress", item->contact->other_po_box);
-                                if (item->contact->other_street)
+                                if (item->contact->other_street.str)
                                     print_ldif_multi("postalAddress", item->contact->other_street);
-                                if (item->contact->other_city)
+                                if (item->contact->other_city.str)
                                     print_ldif_single("l", item->contact->other_city);
-                                if (item->contact->other_state)
+                                if (item->contact->other_state.str)
                                     print_ldif_single("st", item->contact->other_state);
-                                if (item->contact->other_postal_code)
+                                if (item->contact->other_postal_code.str)
                                     print_ldif_single("postalCode", item->contact->other_postal_code);
                             }
                         }
                         else {
                             // new schema, with proper RFC4517 postal addresses
-                            if (item->contact->business_address) {
+                            if (item->contact->business_address.str) {
                                 print_ldif_address("postalAddress", 6,
                                     item->contact->business_po_box,
                                     item->contact->business_street,
@@ -224,22 +268,22 @@
                                     item->contact->business_state,
                                     item->contact->business_postal_code,
                                     item->contact->business_country);
-                                if (item->contact->business_city)
+                                if (item->contact->business_city.str)
                                     print_ldif_single("l", item->contact->business_city);
-                                if (item->contact->business_state)
+                                if (item->contact->business_state.str)
                                     print_ldif_single("st", item->contact->business_state);
-                                if (item->contact->business_postal_code)
+                                if (item->contact->business_postal_code.str)
                                     print_ldif_single("postalCode", item->contact->business_postal_code);
                             }
-                            else if (item->contact->home_address) {
-                                if (item->contact->home_city)
+                            else if (item->contact->home_address.str) {
+                                if (item->contact->home_city.str)
                                     print_ldif_single("l", item->contact->home_city);
-                                if (item->contact->home_state)
+                                if (item->contact->home_state.str)
                                     print_ldif_single("st", item->contact->home_state);
-                                if (item->contact->home_postal_code)
+                                if (item->contact->home_postal_code.str)
                                     print_ldif_single("postalCode", item->contact->home_postal_code);
                             }
-                            else if (item->contact->other_address) {
+                            else if (item->contact->other_address.str) {
                                 print_ldif_address("postalAddress", 6,
                                     item->contact->other_po_box,
                                     item->contact->other_street,
@@ -247,14 +291,14 @@
                                     item->contact->other_state,
                                     item->contact->other_postal_code,
                                     item->contact->other_country);
-                                if (item->contact->other_city)
+                                if (item->contact->other_city.str)
                                     print_ldif_single("l", item->contact->other_city);
-                                if (item->contact->other_state)
+                                if (item->contact->other_state.str)
                                     print_ldif_single("st", item->contact->other_state);
-                                if (item->contact->other_postal_code)
+                                if (item->contact->other_postal_code.str)
                                     print_ldif_single("postalCode", item->contact->other_postal_code);
                             }
-                            if (item->contact->home_address) {
+                            if (item->contact->home_address.str) {
                                 print_ldif_address("homePostalAddress", 6,
                                     item->contact->home_po_box,
                                     item->contact->home_street,
@@ -265,31 +309,31 @@
                             }
                         }
 
-                        if (item->contact->business_fax)
+                        if (item->contact->business_fax.str)
                             print_ldif_single("facsimileTelephoneNumber", item->contact->business_fax);
-                        else if (item->contact->home_fax)
+                        else if (item->contact->home_fax.str)
                             print_ldif_single("facsimileTelephoneNumber", item->contact->home_fax);
 
-                        if (item->contact->business_phone)
+                        if (item->contact->business_phone.str)
                             print_ldif_single("telephoneNumber", item->contact->business_phone);
-                        if (item->contact->home_phone)
+                        if (item->contact->home_phone.str)
                             print_ldif_single("homePhone", item->contact->home_phone);
 
-                        if (item->contact->car_phone)
+                        if (item->contact->car_phone.str)
                             print_ldif_single("mobile", item->contact->car_phone);
-                        else if (item->contact->mobile_phone)
+                        else if (item->contact->mobile_phone.str)
                             print_ldif_single("mobile", item->contact->mobile_phone);
-                        else if (item->contact->other_phone)
+                        else if (item->contact->other_phone.str)
                             print_ldif_single("mobile", item->contact->other_phone);
 
                         if (!old_schema) {
-                            if (item->contact->business_homepage)
+                            if (item->contact->business_homepage.str)
                                 print_ldif_single("labeledURI", item->contact->business_homepage);
-                            if (item->contact->personal_homepage)
+                            if (item->contact->personal_homepage.str)
                                 print_ldif_single("labeledURI", item->contact->personal_homepage);
                         }
 
-                        if (item->comment)
+                        if (item->comment.str)
                             print_ldif_single("description", item->comment);
 
                         for (vector<string>::size_type i=0; i<ldap_class.size(); i++)
@@ -305,6 +349,13 @@
         }
         d_ptr = d_ptr->next;
     }
+    DEBUG_RET();
+}
+
+
+void print_ldif_single(const char *attr, pst_string value)
+{
+    print_ldif_single(attr, value.str);
 }
 
 
@@ -315,7 +366,6 @@
 {
     size_t len;
     bool is_safe_string = true;
-    bool needs_code_conversion = false;
     bool space_flag = false;
 
     // Strip leading spaces
@@ -341,7 +391,6 @@
         }
         else {
             if ((ch & 0x80) == 0x80) {
-                needs_code_conversion = true;
                 is_safe_string = false;
             }
             if (space_flag) {
@@ -354,37 +403,20 @@
     *p = 0;
     if (is_safe_string) {
         printf("%s: %s\n", attr, &buffer[0]);
-        return;
     }
-
-    if (needs_code_conversion && cd != 0) {
-        size_t inlen = p - &buffer[0];
-        size_t utf8_len = 2 * inlen + 1;
-        vector<char> utf8_buffer(utf8_len);
-        char *utf8_p = &utf8_buffer[0];
-
-        iconv(cd, NULL, NULL, NULL, NULL);
-        p = &buffer[0];
-        int ret = iconv(cd, (ICONV_CONST char**)&p, &inlen, &utf8_p, &utf8_len);
-
-        if (ret >= 0) {
-            *utf8_p = 0;
-            p = base64_encode(&utf8_buffer[0], utf8_p - &utf8_buffer[0]);
-        }
-        else
-            p = base64_encode(&buffer[0], buffer.size());
+    else {
+        p = base64_encode(&buffer[0], buffer.size());
+        printf("%s:: %s\n", attr, p);
+        free(p);
     }
-    else
-        p = base64_encode(&buffer[0], buffer.size());
-    printf("%s:: %s\n", attr, p);
-    free(p);
 }
 
 
 // Combines values representing address lines into an address,i
 // lines separated with "$" as per PostalAddress syntax in RFC4517
-void print_ldif_address(const char *attr, int nvalues, char *value, ...)
+void print_ldif_address(const char *attr, int nvalues, pst_string value, ...)
 {
+    DEBUG_ENT("print_ldif_address");
     bool space_flag = false;
     bool newline_flag = false;
     char *address = NULL;    // Buffer where address is built up
@@ -393,26 +425,26 @@
     va_list ap;
 
     va_start(ap, value);
+    while (!value.str) {
+        nvalues--;
+        if (nvalues == 0) {    // Nothing at all to do!
+            va_end(ap);
+            DEBUG_RET();
+            return;
+        }
+        value = va_arg(ap, pst_string);
+    }
 
-    while (!value) {
-       nvalues--;
-       if (nvalues == 0) {    // Nothing at all to do!
-           va_end(ap);
-           return;
-       }
-       value = va_arg(ap, char *);
-    }
     for (;;) {
-        char ch = *value++;
+        char ch = *(value.str)++;
 
-        if (ch == 0 || ch == '\n') {
+        if (ch == 0) {
             do {
-                value = NULL;
                 nvalues--;
                 if (nvalues == 0) break;
-                value = va_arg(ap, char *);
-            } while (!value);
-            if (!value) break;
+                value = va_arg(ap, pst_string);
+            } while (!value.str);
+            if (!nvalues || !value.str) break;
             space_flag = true;
             newline_flag = true;
         }
@@ -449,46 +481,48 @@
     address[i] = 0;
     print_ldif_single(attr, address);
     free(address);
+    DEBUG_RET();
 }
 
 
-void print_ldif_multi(const char *dn, const char *value)
+void print_ldif_multi(const char *dn, pst_string value)
 {
-    const char *n;
-    while ((n = strchr(value, '\n'))) {
-        print_ldif_single(dn, value);
-        value = n + 1;
+    char *n;
+    char *valuestr = value.str;
+    while ((n = strchr(valuestr, '\n'))) {
+        print_ldif_single(dn, valuestr);
+        valuestr = n + 1;
     }
-    print_ldif_single(dn, value);
+    print_ldif_single(dn, valuestr);
 }
 
 
-void print_ldif_two(const char *attr, const char *value1, const char *value2)
+void print_ldif_two(const char *attr, pst_string value1, pst_string value2)
 {
     size_t len1, len2;
-    if (value1 && *value1)
-        len1 = strlen(value1);
+    if (value1.str && *value1.str)
+        len1 = strlen(value1.str);
     else {
         print_ldif_single(attr, value2);
         return;
     }
 
-    if (value2 && *value2)
-        len2 = strlen(value2);
+    if (value2.str && *value2.str)
+        len2 = strlen(value2.str);
     else {
         print_ldif_single(attr, value1);
         return;
     }
 
     vector<char> value(len1 + len2 + 2);
-    memcpy(&value[0], value1, len1);
+    memcpy(&value[0], value1.str, len1);
     value[len1] = ' ';
-    memcpy(&value[0] + len1 + 1, value2, len2 + 1);
+    memcpy(&value[0] + len1 + 1, value2.str, len2 + 1);
     print_ldif_single(attr, &value[0]);
 }
 
 
-void build_cn(char *cn, size_t len, int nvalues, char *value, ...)
+void build_cn(char *cn, size_t len, int nvalues, pst_string value, ...)
 {
     bool space_flag = false;
     size_t i = 0;
@@ -496,26 +530,25 @@
 
     va_start(ap, value);
 
-    while (!value) {
+    while (!value.str) {
        nvalues--;
        if (nvalues == 0) {
            cn[0] = 0;   // Just a terminating NUL
            va_end(ap);
            return;
        }
-       value = va_arg(ap, char *);
+       value = va_arg(ap, pst_string);
     }
     for (;;) {
-        char ch = *value++;
+        char ch = *(value.str)++;
 
         if (ch == 0 || ch == '\n') {
             do {
-                value = NULL;
                 nvalues--;
                 if (nvalues == 0) break;
-                value = va_arg(ap, char *);
-            } while (!value);
-            if (!value) break;
+                value = va_arg(ap, pst_string);
+            } while (!value.str);
+            if (!nvalues || !value.str) break;
             space_flag = true;
         }
         else if (ch == '\r')
@@ -549,7 +582,7 @@
     prog_name = argv[0];
     pst_item *item = NULL;
 
-    while ((c = getopt(argc, argv, "b:c:C:d:l:oVh"))!= -1) {
+    while ((c = getopt(argc, argv, "b:c:d:l:oVh"))!= -1) {
         switch (c) {
         case 'b':
             ldap_base = optarg;
@@ -557,14 +590,6 @@
         case 'c':
             ldap_class.push_back(string(optarg));
             break;
-        case 'C':
-            cd = iconv_open("UTF-8", optarg);
-            if (cd == (iconv_t)(-1)) {
-                fprintf(stderr, "I don't know character set \"%s\"!\n\n", optarg);
-                fprintf(stderr, "Type: \"iconv --list\" to get list of known character sets\n");
-                return 1;
-            }
-            break;
         case 'd':
             d_log = optarg;
             break;
@@ -645,8 +670,6 @@
     pst_close(&pstfile);
     DEBUG_RET();
     free_strings(all_strings);
-    if (cd) iconv_close(cd);
-
     return 0;
 }
 
@@ -656,7 +679,6 @@
     printf("Usage: %s [OPTIONS] {PST FILENAME}\n", prog_name);
     printf("OPTIONS:\n");
     printf("\t-V\t- Version. Display program version\n");
-    printf("\t-C charset\t- assumed character set of non-ASCII characters\n");
     printf("\t-b ldapbase\t- set the LDAP base value\n");
     printf("\t-c class\t- set the class of the LDAP objects (may contain more than one)\n");
     printf("\t-d <filename>\t- Debug to file. This is a binary log. Use readpstlog to print it\n");
@@ -695,14 +717,15 @@
 
 
 // This function escapes Distinguished Names (as per RFC4514)
-void print_ldif_dn(const char *attr, const char *value, const char *base)
+void print_ldif_dn(const char *attr, pst_string value, const char *base)
 {
     printf("dn: cn=");
+    const char *valuestr = value.str;
     // remove leading spaces (RFC says escape them)
-    while (*value == ' ')
-        value++;
+    while (*valuestr == ' ')
+        valuestr++;
 
-    print_escaped_dn(value);
+    print_escaped_dn(valuestr);
     if (base && base[0]) {
         printf(", %s", base);
     }
@@ -714,34 +737,6 @@
 void print_escaped_dn(const char *value)
 {
     char ch;
-    bool needs_code_conversion = false;
-    char *utf8_buffer = NULL;
-
-    // First do a quick scan to see if any code conversion is required
-    if (cd) {
-        const char *p = value;
-        while (*p) {
-            if (*p++ & 0x80) {
-                needs_code_conversion = true;
-                break;
-            }
-        }
-    }
-
-    if (needs_code_conversion) {
-        size_t inlen = strlen(value);
-        size_t utf8_len = 2 * inlen + 1;
-        char *p = (char *)value;
-        char *utf8_p = utf8_buffer;
-
-        utf8_buffer = (char *)malloc(utf8_len);
-        utf8_p = utf8_buffer;
-        iconv(cd, NULL, NULL, NULL, NULL);
-        if (iconv(cd, (ICONV_CONST char**)&p, &inlen, &utf8_p, &utf8_len) >= 0) {
-            *utf8_p = 0;
-            value = utf8_buffer;
-        }
-    }
 
     // escape initial '#' and space
     if (*value == '#' || *value == ' ')
@@ -765,6 +760,5 @@
                 putchar(ch);
         }
     }
-    if (utf8_buffer) free((void *)utf8_buffer);
     return;
 }
--- a/src/readpst.c	Thu Mar 05 08:23:32 2009 -0800
+++ b/src/readpst.c	Sun Mar 08 14:35:26 2009 -0700
@@ -51,11 +51,11 @@
 int       test_base64(char *body);
 void      find_html_charset(char *html, char *charset, size_t charsetlen);
 void      find_rfc822_headers(char** extra_mime_headers);
-void      write_body_part(FILE* f_output, char *body, int32_t body_was_unicode, char *mime, char *charset, char *boundary, pst_file* pst);
+void      write_body_part(FILE* f_output, pst_string *body, char *mime, char *charset, char *boundary, pst_file* pst);
 void      write_normal_email(FILE* f_output, char f_name[], pst_item* item, int mode, int mode_MH, pst_file* pst, int save_rtf, char** extra_mime_headers);
-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      write_vcard(FILE* f_output, pst_item *item, pst_item_contact* contact, char comment[]);
+void      write_appointment(FILE* f_output, pst_item *item, pst_item_appointment* appointment,
+                            FILETIME* create_date, FILETIME* modify_date);
 void      create_enter_dir(struct file_ll* f, pst_item *item);
 void      close_enter_dir(struct file_ll *f);
 
@@ -140,13 +140,13 @@
 
             item = pst_parse_item(&pstfile, d_ptr, NULL);
             DEBUG_MAIN(("main: About to process item\n"));
-            if (item && item->email && item->email->subject && item->email->subject->subj) {
-                DEBUG_EMAIL(("item->email->subject->subj = %s\n", item->email->subject->subj));
+            if (item && item->subject.str) {
+                DEBUG_EMAIL(("item->subject = %s\n", item->subject.str));
             }
             if (item) {
-                if (item->folder && d_ptr->child && (deleted_mode == DMODE_INCLUDE || strcasecmp(item->file_as, "Deleted Items"))) {
+                if (item->folder && d_ptr->child && item->file_as.str && (deleted_mode == DMODE_INCLUDE || strcasecmp(item->file_as.str, "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);
+                    if (output_mode != OUTPUT_QUIET) printf("Processing Folder \"%s\"\n", item->file_as.str);
                     process(item, d_ptr->child);
 
                 } else if (item->contact && (item->type == PST_TYPE_CONTACT)) {
@@ -159,10 +159,15 @@
                     if (ff.type != PST_TYPE_CONTACT) {
                         DEBUG_MAIN(("main: I have a contact, but the folder isn't a contacts folder. Processing anyway\n"));
                     }
-                    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);
+                    if (contact_mode == CMODE_VCARD) {
+                        pst_convert_utf8_null(item, &item->comment);
+                        write_vcard(ff.output, item, item->contact, item->comment.str);
+                    }
+                    else {
+                        pst_convert_utf8(item, &item->contact->fullname);
+                        pst_convert_utf8(item, &item->contact->address1);
+                        fprintf(ff.output, "%s <%s>\n", item->contact->fullname.str, item->contact->address1.str);
+                    }
 
                 } else if (item->email && (item->type == PST_TYPE_NOTE || item->type == PST_TYPE_REPORT || item->type == PST_TYPE_OTHER)) {
                     char *extra_mime_headers = NULL;
@@ -183,10 +188,14 @@
                         DEBUG_MAIN(("main: I have a journal entry, but the folder isn't a journal folder. Processing anyway\n"));
                     }
                     fprintf(ff.output, "BEGIN:VJOURNAL\n");
-                    if (item->email && item->email->subject && item->email->subject->subj)
-                        fprintf(ff.output, "SUMMARY:%s\n", pst_rfc2426_escape(item->email->subject->subj));
-                    if (item->email && item->email->body)
-                        fprintf(ff.output, "DESCRIPTION:%s\n", pst_rfc2426_escape(item->email->body));
+                    if (item->subject.str) {
+                        pst_convert_utf8(item, &item->subject);
+                        fprintf(ff.output, "SUMMARY:%s\n", pst_rfc2426_escape(item->subject.str));
+                    }
+                    if (item->body.str) {
+                        pst_convert_utf8(item, &item->body);
+                        fprintf(ff.output, "DESCRIPTION:%s\n", pst_rfc2426_escape(item->body.str));
+                    }
                     if (item->journal->start)
                         fprintf(ff.output, "DTSTART;VALUE=DATE-TIME:%s\n", pst_rfc2445_datetime_format(item->journal->start));
                     fprintf(ff.output, "END:VJOURNAL\n\n");
@@ -199,7 +208,7 @@
                     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);
+                    write_appointment(ff.output, item, item->appointment, item->create_date, item->modify_date);
 
                 } else if (item->message_store) {
                     // there should only be one message_store, and we have already done it
@@ -209,7 +218,7 @@
                     // these all seem to be things that MS agrees are not included in the item count
                     //ff.skip_count++;
                     DEBUG_MAIN(("main: Unknown item type %i (%s) name (%s)\n",
-                                item->type, item->ascii_type, item->file_as));
+                                item->type, item->ascii_type, item->file_as.str));
                 }
                 pst_freeItem(item);
             } else {
@@ -324,17 +333,17 @@
         char   buf[1024];
         size_t l = 0;
         if (NULL == (fp = fopen(fname, "rb"))) {
-            fprintf(stderr, "Couldn't open file %s\n", fname );
+            WARN(("Couldn't open file %s\n", fname));
             DEBUG_RET();
             return 1;
         }
 
         while (0 != (l = fread(buf, 1, 1024, fp))) {
             if (0 != pst_decrypt(0, buf, l, PST_COMP_ENCRYPT))
-                fprintf(stderr, "pst_decrypt() failed (I'll try to continue)\n");
+                WARN(("pst_decrypt() failed (I'll try to continue)\n"));
 
             if (l != pst_fwrite(buf, 1, l, stdout)) {
-                fprintf(stderr, "Couldn't output to stdout?\n");
+                WARN(("Couldn't output to stdout?\n"));
                 DEBUG_RET();
                 return 1;
             }
@@ -367,7 +376,7 @@
     }
 
     // default the file_as to the same as the main filename if it doesn't exist
-    if (!item->file_as) {
+    if (!item->file_as.str) {
         if (!(temp = strrchr(fname, '/')))
             if (!(temp = strrchr(fname, '\\')))
                 temp = fname;
@@ -375,11 +384,12 @@
                 temp++; // get past the "\\"
         else
             temp++; // get past the "/"
-        item->file_as = (char*)xmalloc(strlen(temp)+1);
-        strcpy(item->file_as, temp);
-        DEBUG_MAIN(("file_as was blank, so am using %s\n", item->file_as));
+        item->file_as.str = (char*)xmalloc(strlen(temp)+1);
+        strcpy(item->file_as.str, temp);
+        item->file_as.is_utf8 = 1;
+        DEBUG_MAIN(("file_as was blank, so am using %s\n", item->file_as.str));
     }
-    DEBUG_MAIN(("main: Root Folder Name: %s\n", item->file_as));
+    DEBUG_MAIN(("main: Root Folder Name: %s\n", item->file_as.str));
 
     d_ptr = pst_getTopOfFolders(&pstfile, item);
     if (!d_ptr) {
@@ -398,7 +408,6 @@
 
 void write_email_body(FILE *f, char *body) {
     char *n = body;
-    //  DEBUG_MAIN(("write_email_body(): \"%s\"\n", body));
     DEBUG_ENT("write_email_body");
     while (n) {
         if (strncmp(body, "From ", 5) == 0)
@@ -700,8 +709,8 @@
 
     // If there is a long filename (filename2) use that, otherwise
     // use the 8.3 filename (filename1)
-    char *attach_filename = (attach->filename2) ? attach->filename2
-                                                        : attach->filename1;
+    char *attach_filename = (attach->filename2.str) ? attach->filename2.str
+                                                    : attach->filename1.str;
     DEBUG_ENT("write_separate_attachment");
 
     check_filename(f_name);
@@ -744,7 +753,7 @@
     pst_index_ll *ptr;
     DEBUG_ENT("write_embedded_message");
     fprintf(f_output, "\n--%s\n", boundary);
-    fprintf(f_output, "Content-Type: %s\n\n", attach->mimetype);
+    fprintf(f_output, "Content-Type: %s\n\n", attach->mimetype.str);
     ptr = pst_getID(pf, attach->id_val);
 
     pst_desc_ll d_ptr;
@@ -792,16 +801,16 @@
     }
 
     fprintf(f_output, "\n--%s\n", boundary);
-    if (!attach->mimetype) {
+    if (!attach->mimetype.str) {
         fprintf(f_output, "Content-Type: %s\n", MIME_TYPE_DEFAULT);
     } else {
-        fprintf(f_output, "Content-Type: %s\n", attach->mimetype);
+        fprintf(f_output, "Content-Type: %s\n", attach->mimetype.str);
     }
     fprintf(f_output, "Content-Transfer-Encoding: base64\n");
 
     // If there is a long filename (filename2) use that, otherwise
     // use the 8.3 filename (filename1)
-    attach_filename = (attach->filename2) ? attach->filename2 : attach->filename1;
+    attach_filename = (attach->filename2.str) ? attach->filename2.str : attach->filename1.str;
     if (!attach_filename) {
         fprintf(f_output, "Content-Disposition: inline\n\n");
     } else {
@@ -986,18 +995,17 @@
 }
 
 
-void write_body_part(FILE* f_output, char *body, int32_t body_was_unicode, char *mime, char *charset, char *boundary, pst_file* pst)
+void write_body_part(FILE* f_output, pst_string *body, char *mime, char *charset, char *boundary, pst_file* pst)
 {
-    char *needfree = NULL;
     DEBUG_ENT("write_body_part");
-    if (body_was_unicode && (strcasecmp("utf-8", charset))) {
+    if (body->is_utf8 && (strcasecmp("utf-8", charset))) {
         // try to convert to the specified charset since the target
         // is not utf-8, and the data came from a unicode (utf16) field
         // and is now in utf-8.
         size_t rc;
         DEBUG_EMAIL(("Convert %s utf-8 to %s\n", mime, charset));
         vbuf *newer = vballoc(2);
-        rc = vb_utf8to8bit(newer, body, strlen(body) + 1, charset);
+        rc = vb_utf8to8bit(newer, body->str, strlen(body->str) + 1, charset);
         if (rc == (size_t)-1) {
             // unable to convert, change the charset to utf8
             free(newer->b);
@@ -1005,18 +1013,19 @@
             charset = "utf-8";
         }
         else {
-            needfree = body = newer->b;
+            free(body->str);
+            body->str = newer->b;
         }
         free(newer);
     }
-    removeCR(body);
-    int base64 = test_base64(body);
+    removeCR(body->str);
+    int base64 = test_base64(body->str);
     fprintf(f_output, "\n--%s\n", boundary);
     fprintf(f_output, "Content-Type: %s; charset=\"%s\"\n", mime, charset);
     if (base64) fprintf(f_output, "Content-Transfer-Encoding: base64\n");
     fprintf(f_output, "\n");
     if (base64) {
-        char *enc = base64_encode(body, strlen(body));
+        char *enc = base64_encode(body->str, strlen(body->str));
         if (enc) {
             write_email_body(f_output, enc);
             fprintf(f_output, "\n");
@@ -1024,46 +1033,12 @@
         }
     }
     else {
-        write_email_body(f_output, body);
+        write_email_body(f_output, body->str);
     }
-    if (needfree) free(needfree);
     DEBUG_RET();
 }
 
 
-const char* codepage(int cp);
-const char* codepage(int cp) {
-    static char buffer[20];
-    switch (cp) {
-        case   932 : return "iso-2022-jp";
-        case   936 : return "gb2313";
-        case   950 : return "big5";
-        case 20127 : return "us-ascii";
-        case 20269 : return "iso-6937";
-        case 20865 : return "iso-8859-15";
-        case 20866 : return "koi8-r";
-        case 21866 : return "koi8-u";
-        case 28591 : return "iso-8859-1";
-        case 28592 : return "iso-8859-2";
-        case 28595 : return "iso-8859-5";
-        case 28596 : return "iso-8859-6";
-        case 28597 : return "iso-8859-7";
-        case 28598 : return "iso-8859-8";
-        case 28599 : return "iso-8859-9";
-        case 50220 : return "iso-2022-jp";
-        case 50221 : return "csiso2022jp";
-        case 51932 : return "euc-jp";
-        case 51949 : return "euc-kr";
-        case 65000 : return "utf-7";
-        case 65001 : return "utf-8";
-        default :
-            snprintf(buffer, sizeof(buffer), "windows-%d", cp);
-            return buffer;
-    }
-    return NULL;
-}
-
-
 void write_normal_email(FILE* f_output, char f_name[], pst_item* item, int mode, int mode_MH, pst_file* pst, int save_rtf, char** extra_mime_headers)
 {
     char boundary[60];
@@ -1075,28 +1050,30 @@
     int attach_num;
     time_t em_time;
     char *c_time;
-    char *headers = (item->email->header) ? item->email->header : *extra_mime_headers;
+    char *headers = NULL;
     int has_from, has_subject, has_to, has_cc, has_date, has_msgid;
     has_from = has_subject = has_to = has_cc = has_date = has_msgid = 0;
     DEBUG_ENT("write_normal_email");
 
+    pst_convert_utf8_null(item, &item->email->header);
+    headers = (item->email->header.str) ? item->email->header.str : *extra_mime_headers;
+
     // setup default body character set and report type
-    snprintf(body_charset, sizeof(body_charset), "%s",
-        (item->body_charset)     ? item->body_charset :
-        (item->message_codepage) ? codepage(item->message_codepage) :
-        (item->internet_cpid)    ? codepage(item->internet_cpid) :
-        "utf-8");
+    strncpy(body_charset, pst_default_charset(item), sizeof(body_charset));
+    body_charset[sizeof(body_charset)-1] = '\0';
     body_report[0] = '\0';
 
     // setup default sender
-    if (item->email->sender_address && strchr(item->email->sender_address, '@')) {
-        temp = item->email->sender_address;
+    pst_convert_utf8(item, &item->email->sender_address);
+    if (item->email->sender_address.str && strchr(item->email->sender_address.str, '@')) {
+        temp = item->email->sender_address.str;
         sender_known = 1;
     }
     else {
         temp = "MAILER-DAEMON";
     }
-    snprintf(sender, sizeof(sender), "%s", temp);
+    strncpy(sender, temp, sizeof(sender));
+    sender[sizeof(sender)-1] = '\0';
 
     // convert the sent date if it exists, or set it to a fixed date
     if (item->email->sent_date) {
@@ -1171,8 +1148,9 @@
 
     DEBUG_EMAIL(("About to print Header\n"));
 
-    if (item && item->email && item->email->subject && item->email->subject->subj) {
-        DEBUG_EMAIL(("item->email->subject->subj = %s\n", item->email->subject->subj));
+    if (item && item->subject.str) {
+        pst_convert_utf8(item, &item->subject);
+        DEBUG_EMAIL(("item->subject = %s\n", item->subject.str));
     }
 
     if (mode != MODE_SEPARATE) {
@@ -1195,23 +1173,25 @@
     // create required header fields that are not already written
 
     if (!has_from) {
-        fprintf(f_output, "From: \"%s\" <%s>\n", item->email->outlook_sender_name, sender);
+        fprintf(f_output, "From: \"%s\" <%s>\n", item->email->outlook_sender_name.str, sender);
     }
 
     if (!has_subject) {
-        if (item->email->subject && item->email->subject->subj) {
-            fprintf(f_output, "Subject: %s\n", item->email->subject->subj);
+        if (item->subject.str) {
+            fprintf(f_output, "Subject: %s\n", item->subject.str);
         } else {
             fprintf(f_output, "Subject: \n");
         }
     }
 
-    if (!has_to && item->email->sentto_address) {
-        fprintf(f_output, "To: %s\n", item->email->sentto_address);
+    if (!has_to && item->email->sentto_address.str) {
+        pst_convert_utf8(item, &item->email->sentto_address);
+        fprintf(f_output, "To: %s\n", item->email->sentto_address.str);
     }
 
-    if (!has_cc && item->email->cc_address) {
-        fprintf(f_output, "Cc: %s\n", item->email->cc_address);
+    if (!has_cc && item->email->cc_address.str) {
+        pst_convert_utf8(item, &item->email->cc_address);
+        fprintf(f_output, "Cc: %s\n", item->email->cc_address.str);
     }
 
     if (!has_date && item->email->sent_date) {
@@ -1220,19 +1200,22 @@
         fprintf(f_output, "Date: %s\n", c_time);
     }
 
-    if (!has_msgid && item->email->messageid) {
-        fprintf(f_output, "Message-Id: %s\n", item->email->messageid);
+    if (!has_msgid && item->email->messageid.str) {
+        pst_convert_utf8(item, &item->email->messageid);
+        fprintf(f_output, "Message-Id: %s\n", item->email->messageid.str);
     }
 
     // add forensic headers to capture some .pst stuff that is not really
     // needed or used by mail clients
-    if (item->email->sender_address && !strchr(item->email->sender_address, '@')
-                                    && strcmp(item->email->sender_address, ".")) {
-        fprintf(f_output, "X-libpst-forensic-sender: %s\n", item->email->sender_address);
+    pst_convert_utf8_null(item, &item->email->sender_address);
+    if (item->email->sender_address.str && !strchr(item->email->sender_address.str, '@')
+                                        && strcmp(item->email->sender_address.str, ".")) {
+        fprintf(f_output, "X-libpst-forensic-sender: %s\n", item->email->sender_address.str);
     }
 
-    if (item->email->bcc_address) {
-        fprintf(f_output, "X-libpst-forensic-bcc: %s\n", item->email->bcc_address);
+    if (item->email->bcc_address.str) {
+        pst_convert_utf8(item, &item->email->bcc_address);
+        fprintf(f_output, "X-libpst-forensic-bcc: %s\n", item->email->bcc_address.str);
     }
 
     // add our own mime headers
@@ -1253,18 +1236,18 @@
     fprintf(f_output, "\n");    // end of headers, start of body
 
     // now dump the body parts
-    if (item->email->body) {
-        write_body_part(f_output, item->email->body, item->email->body_was_unicode, "text/plain", body_charset, boundary, pst);
+    if (item->body.str) {
+        write_body_part(f_output, &item->body, "text/plain", body_charset, boundary, pst);
     }
 
-    if ((item->email->report_text) && (body_report[0] != '\0')) {
-        write_body_part(f_output, item->email->report_text, item->email->report_was_unicode, "text/plain", body_charset, boundary, pst);
+    if ((item->email->report_text.str) && (body_report[0] != '\0')) {
+        write_body_part(f_output, &item->email->report_text, "text/plain", body_charset, boundary, pst);
         fprintf(f_output, "\n");
     }
 
-    if (item->email->htmlbody) {
-        find_html_charset(item->email->htmlbody, body_charset, sizeof(body_charset));
-        write_body_part(f_output, item->email->htmlbody, item->email->htmlbody_was_unicode, "text/html", body_charset, boundary, pst);
+    if (item->email->htmlbody.str) {
+        find_html_charset(item->email->htmlbody.str, body_charset, sizeof(body_charset));
+        write_body_part(f_output, &item->email->htmlbody, "text/html", body_charset, boundary, pst);
     }
 
     if (item->email->rtf_compressed && save_rtf) {
@@ -1274,8 +1257,10 @@
         attach->next = item->attach;
         item->attach = attach;
         attach->data = lzfu_decompress(item->email->rtf_compressed, item->email->rtf_compressed_size, &attach->size);
-        attach->filename2 = strdup(RTF_ATTACH_NAME);
-        attach->mimetype  = strdup(RTF_ATTACH_TYPE);
+        attach->filename2.str     = strdup(RTF_ATTACH_NAME);
+        attach->filename2.is_utf8 = 1;
+        attach->mimetype.str      = strdup(RTF_ATTACH_TYPE);
+        attach->mimetype.is_utf8  = 1;
     }
 
     if (item->email->encrypted_body || item->email->encrypted_htmlbody) {
@@ -1311,8 +1296,11 @@
         pst_item_attach* attach;
         attach_num = 0;
         for (attach = item->attach; attach; attach = attach->next) {
+            pst_convert_utf8_null(item, &attach->filename1);
+            pst_convert_utf8_null(item, &attach->filename2);
+            pst_convert_utf8_null(item, &attach->mimetype);
             DEBUG_EMAIL(("Attempting Attachment encoding\n"));
-            if (!attach->data && attach->mimetype && !strcmp(attach->mimetype, RFC822)) {
+            if (!attach->data && attach->mimetype.str && !strcmp(attach->mimetype.str, RFC822)) {
                 DEBUG_EMAIL(("seem to have special embedded message attachment\n"));
                 find_rfc822_headers(extra_mime_headers);
                 write_embedded_message(f_output, attach, boundary, pst, extra_mime_headers);
@@ -1334,95 +1322,149 @@
 }
 
 
-void write_vcard(FILE* f_output, pst_item_contact* contact, char comment[])
+void write_vcard(FILE* f_output, pst_item *item, 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");
+
+    // make everything utf8
+    pst_convert_utf8_null(item, &contact->fullname);
+    pst_convert_utf8_null(item, &contact->surname);
+    pst_convert_utf8_null(item, &contact->first_name);
+    pst_convert_utf8_null(item, &contact->middle_name);
+    pst_convert_utf8_null(item, &contact->display_name_prefix);
+    pst_convert_utf8_null(item, &contact->suffix);
+    pst_convert_utf8_null(item, &contact->nickname);
+    pst_convert_utf8_null(item, &contact->address1);
+    pst_convert_utf8_null(item, &contact->address2);
+    pst_convert_utf8_null(item, &contact->address3);
+    pst_convert_utf8_null(item, &contact->home_po_box);
+    pst_convert_utf8_null(item, &contact->home_street);
+    pst_convert_utf8_null(item, &contact->home_city);
+    pst_convert_utf8_null(item, &contact->home_state);
+    pst_convert_utf8_null(item, &contact->home_postal_code);
+    pst_convert_utf8_null(item, &contact->home_country);
+    pst_convert_utf8_null(item, &contact->home_address);
+    pst_convert_utf8_null(item, &contact->business_po_box);
+    pst_convert_utf8_null(item, &contact->business_street);
+    pst_convert_utf8_null(item, &contact->business_city);
+    pst_convert_utf8_null(item, &contact->business_state);
+    pst_convert_utf8_null(item, &contact->business_postal_code);
+    pst_convert_utf8_null(item, &contact->business_country);
+    pst_convert_utf8_null(item, &contact->business_address);
+    pst_convert_utf8_null(item, &contact->other_po_box);
+    pst_convert_utf8_null(item, &contact->other_street);
+    pst_convert_utf8_null(item, &contact->other_city);
+    pst_convert_utf8_null(item, &contact->other_state);
+    pst_convert_utf8_null(item, &contact->other_postal_code);
+    pst_convert_utf8_null(item, &contact->other_country);
+    pst_convert_utf8_null(item, &contact->other_address);
+    pst_convert_utf8_null(item, &contact->business_fax);
+    pst_convert_utf8_null(item, &contact->business_phone);
+    pst_convert_utf8_null(item, &contact->business_phone2);
+    pst_convert_utf8_null(item, &contact->car_phone);
+    pst_convert_utf8_null(item, &contact->home_fax);
+    pst_convert_utf8_null(item, &contact->home_phone);
+    pst_convert_utf8_null(item, &contact->home_phone2);
+    pst_convert_utf8_null(item, &contact->isdn_phone);
+    pst_convert_utf8_null(item, &contact->mobile_phone);
+    pst_convert_utf8_null(item, &contact->other_phone);
+    pst_convert_utf8_null(item, &contact->pager_phone);
+    pst_convert_utf8_null(item, &contact->primary_fax);
+    pst_convert_utf8_null(item, &contact->primary_phone);
+    pst_convert_utf8_null(item, &contact->radio_phone);
+    pst_convert_utf8_null(item, &contact->telex);
+    pst_convert_utf8_null(item, &contact->job_title);
+    pst_convert_utf8_null(item, &contact->profession);
+    pst_convert_utf8_null(item, &contact->assistant_name);
+    pst_convert_utf8_null(item, &contact->assistant_phone);
+    pst_convert_utf8_null(item, &contact->company_name);
+
     // the specification I am following is (hopefully) RFC2426 vCard Mime Directory Profile
     fprintf(f_output, "BEGIN:VCARD\n");
-    fprintf(f_output, "FN:%s\n", pst_rfc2426_escape(contact->fullname));
+    fprintf(f_output, "FN:%s\n", pst_rfc2426_escape(contact->fullname.str));
 
     //fprintf(f_output, "N:%s;%s;%s;%s;%s\n",
-    fprintf(f_output, "N:%s;", (!contact->surname)             ? "" : pst_rfc2426_escape(contact->surname));
-    fprintf(f_output, "%s;",   (!contact->first_name)          ? "" : pst_rfc2426_escape(contact->first_name));
-    fprintf(f_output, "%s;",   (!contact->middle_name)         ? "" : pst_rfc2426_escape(contact->middle_name));
-    fprintf(f_output, "%s;",   (!contact->display_name_prefix) ? "" : pst_rfc2426_escape(contact->display_name_prefix));
-    fprintf(f_output, "%s\n",  (!contact->suffix)              ? "" : pst_rfc2426_escape(contact->suffix));
+    fprintf(f_output, "N:%s;", (!contact->surname.str)             ? "" : pst_rfc2426_escape(contact->surname.str));
+    fprintf(f_output, "%s;",   (!contact->first_name.str)          ? "" : pst_rfc2426_escape(contact->first_name.str));
+    fprintf(f_output, "%s;",   (!contact->middle_name.str)         ? "" : pst_rfc2426_escape(contact->middle_name.str));
+    fprintf(f_output, "%s;",   (!contact->display_name_prefix.str) ? "" : pst_rfc2426_escape(contact->display_name_prefix.str));
+    fprintf(f_output, "%s\n",  (!contact->suffix.str)              ? "" : pst_rfc2426_escape(contact->suffix.str));
 
-    if (contact->nickname)
-        fprintf(f_output, "NICKNAME:%s\n", pst_rfc2426_escape(contact->nickname));
-    if (contact->address1)
-        fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address1));
-    if (contact->address2)
-        fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address2));
-    if (contact->address3)
-        fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address3));
+    if (contact->nickname.str)
+        fprintf(f_output, "NICKNAME:%s\n", pst_rfc2426_escape(contact->nickname.str));
+    if (contact->address1.str)
+        fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address1.str));
+    if (contact->address2.str)
+        fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address2.str));
+    if (contact->address3.str)
+        fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address3.str));
     if (contact->birthday)
         fprintf(f_output, "BDAY:%s\n", pst_rfc2425_datetime_format(contact->birthday));
 
-    if (contact->home_address) {
+    if (contact->home_address.str) {
         //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)      ? "" : pst_rfc2426_escape(contact->home_po_box));
+        fprintf(f_output, "ADR;TYPE=home:%s;",  (!contact->home_po_box.str)      ? "" : pst_rfc2426_escape(contact->home_po_box.str));
         fprintf(f_output, "%s;",                ""); // extended Address
-        fprintf(f_output, "%s;",                (!contact->home_street)      ? "" : pst_rfc2426_escape(contact->home_street));
-        fprintf(f_output, "%s;",                (!contact->home_city)        ? "" : pst_rfc2426_escape(contact->home_city));
-        fprintf(f_output, "%s;",                (!contact->home_state)       ? "" : pst_rfc2426_escape(contact->home_state));
-        fprintf(f_output, "%s;",                (!contact->home_postal_code) ? "" : pst_rfc2426_escape(contact->home_postal_code));
-        fprintf(f_output, "%s\n",               (!contact->home_country)     ? "" : pst_rfc2426_escape(contact->home_country));
-        fprintf(f_output, "LABEL;TYPE=home:%s\n", pst_rfc2426_escape(contact->home_address));
+        fprintf(f_output, "%s;",                (!contact->home_street.str)      ? "" : pst_rfc2426_escape(contact->home_street.str));
+        fprintf(f_output, "%s;",                (!contact->home_city.str)        ? "" : pst_rfc2426_escape(contact->home_city.str));
+        fprintf(f_output, "%s;",                (!contact->home_state.str)       ? "" : pst_rfc2426_escape(contact->home_state.str));
+        fprintf(f_output, "%s;",                (!contact->home_postal_code.str) ? "" : pst_rfc2426_escape(contact->home_postal_code.str));
+        fprintf(f_output, "%s\n",               (!contact->home_country.str)     ? "" : pst_rfc2426_escape(contact->home_country.str));
+        fprintf(f_output, "LABEL;TYPE=home:%s\n", pst_rfc2426_escape(contact->home_address.str));
     }
 
-    if (contact->business_address) {
+    if (contact->business_address.str) {
         //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)      ? "" : pst_rfc2426_escape(contact->business_po_box));
+        fprintf(f_output, "ADR;TYPE=work:%s;",  (!contact->business_po_box.str)      ? "" : pst_rfc2426_escape(contact->business_po_box.str));
         fprintf(f_output, "%s;",                ""); // extended Address
-        fprintf(f_output, "%s;",                (!contact->business_street)      ? "" : pst_rfc2426_escape(contact->business_street));
-        fprintf(f_output, "%s;",                (!contact->business_city)        ? "" : pst_rfc2426_escape(contact->business_city));
-        fprintf(f_output, "%s;",                (!contact->business_state)       ? "" : pst_rfc2426_escape(contact->business_state));
-        fprintf(f_output, "%s;",                (!contact->business_postal_code) ? "" : pst_rfc2426_escape(contact->business_postal_code));
-        fprintf(f_output, "%s\n",               (!contact->business_country)     ? "" : pst_rfc2426_escape(contact->business_country));
-        fprintf(f_output, "LABEL;TYPE=work:%s\n", pst_rfc2426_escape(contact->business_address));
+        fprintf(f_output, "%s;",                (!contact->business_street.str)      ? "" : pst_rfc2426_escape(contact->business_street.str));
+        fprintf(f_output, "%s;",                (!contact->business_city.str)        ? "" : pst_rfc2426_escape(contact->business_city.str));
+        fprintf(f_output, "%s;",                (!contact->business_state.str)       ? "" : pst_rfc2426_escape(contact->business_state.str));
+        fprintf(f_output, "%s;",                (!contact->business_postal_code.str) ? "" : pst_rfc2426_escape(contact->business_postal_code.str));
+        fprintf(f_output, "%s\n",               (!contact->business_country.str)     ? "" : pst_rfc2426_escape(contact->business_country.str));
+        fprintf(f_output, "LABEL;TYPE=work:%s\n", pst_rfc2426_escape(contact->business_address.str));
     }
 
-    if (contact->other_address) {
+    if (contact->other_address.str) {
         //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)       ? "" : pst_rfc2426_escape(contact->other_po_box));
+        fprintf(f_output, "ADR;TYPE=postal:%s;",(!contact->other_po_box.str)       ? "" : pst_rfc2426_escape(contact->other_po_box.str));
         fprintf(f_output, "%s;",                ""); // extended Address
-        fprintf(f_output, "%s;",                (!contact->other_street)       ? "" : pst_rfc2426_escape(contact->other_street));
-        fprintf(f_output, "%s;",                (!contact->other_city)         ? "" : pst_rfc2426_escape(contact->other_city));
-        fprintf(f_output, "%s;",                (!contact->other_state)        ? "" : pst_rfc2426_escape(contact->other_state));
-        fprintf(f_output, "%s;",                (!contact->other_postal_code)  ? "" : pst_rfc2426_escape(contact->other_postal_code));
-        fprintf(f_output, "%s\n",               (!contact->other_country)      ? "" : pst_rfc2426_escape(contact->other_country));
-        fprintf(f_output, "LABEL;TYPE=postal:%s\n", pst_rfc2426_escape(contact->other_address));
+        fprintf(f_output, "%s;",                (!contact->other_street.str)       ? "" : pst_rfc2426_escape(contact->other_street.str));
+        fprintf(f_output, "%s;",                (!contact->other_city.str)         ? "" : pst_rfc2426_escape(contact->other_city.str));
+        fprintf(f_output, "%s;",                (!contact->other_state.str)        ? "" : pst_rfc2426_escape(contact->other_state.str));
+        fprintf(f_output, "%s;",                (!contact->other_postal_code.str)  ? "" : pst_rfc2426_escape(contact->other_postal_code.str));
+        fprintf(f_output, "%s\n",               (!contact->other_country.str)      ? "" : pst_rfc2426_escape(contact->other_country.str));
+        fprintf(f_output, "LABEL;TYPE=postal:%s\n", pst_rfc2426_escape(contact->other_address.str));
     }
 
-    if (contact->business_fax)      fprintf(f_output, "TEL;TYPE=work,fax:%s\n",         pst_rfc2426_escape(contact->business_fax));
-    if (contact->business_phone)    fprintf(f_output, "TEL;TYPE=work,voice:%s\n",       pst_rfc2426_escape(contact->business_phone));
-    if (contact->business_phone2)   fprintf(f_output, "TEL;TYPE=work,voice:%s\n",       pst_rfc2426_escape(contact->business_phone2));
-    if (contact->car_phone)         fprintf(f_output, "TEL;TYPE=car,voice:%s\n",        pst_rfc2426_escape(contact->car_phone));
-    if (contact->home_fax)          fprintf(f_output, "TEL;TYPE=home,fax:%s\n",         pst_rfc2426_escape(contact->home_fax));
-    if (contact->home_phone)        fprintf(f_output, "TEL;TYPE=home,voice:%s\n",       pst_rfc2426_escape(contact->home_phone));
-    if (contact->home_phone2)       fprintf(f_output, "TEL;TYPE=home,voice:%s\n",       pst_rfc2426_escape(contact->home_phone2));
-    if (contact->isdn_phone)        fprintf(f_output, "TEL;TYPE=isdn:%s\n",             pst_rfc2426_escape(contact->isdn_phone));
-    if (contact->mobile_phone)      fprintf(f_output, "TEL;TYPE=cell,voice:%s\n",       pst_rfc2426_escape(contact->mobile_phone));
-    if (contact->other_phone)       fprintf(f_output, "TEL;TYPE=msg:%s\n",              pst_rfc2426_escape(contact->other_phone));
-    if (contact->pager_phone)       fprintf(f_output, "TEL;TYPE=pager:%s\n",            pst_rfc2426_escape(contact->pager_phone));
-    if (contact->primary_fax)       fprintf(f_output, "TEL;TYPE=fax,pref:%s\n",         pst_rfc2426_escape(contact->primary_fax));
-    if (contact->primary_phone)     fprintf(f_output, "TEL;TYPE=phone,pref:%s\n",       pst_rfc2426_escape(contact->primary_phone));
-    if (contact->radio_phone)       fprintf(f_output, "TEL;TYPE=pcs:%s\n",              pst_rfc2426_escape(contact->radio_phone));
-    if (contact->telex)             fprintf(f_output, "TEL;TYPE=bbs:%s\n",              pst_rfc2426_escape(contact->telex));
-    if (contact->job_title)         fprintf(f_output, "TITLE:%s\n",                     pst_rfc2426_escape(contact->job_title));
-    if (contact->profession)        fprintf(f_output, "ROLE:%s\n",                      pst_rfc2426_escape(contact->profession));
-    if (contact->assistant_name || contact->assistant_phone) {
+    if (contact->business_fax.str)      fprintf(f_output, "TEL;TYPE=work,fax:%s\n",         pst_rfc2426_escape(contact->business_fax.str));
+    if (contact->business_phone.str)    fprintf(f_output, "TEL;TYPE=work,voice:%s\n",       pst_rfc2426_escape(contact->business_phone.str));
+    if (contact->business_phone2.str)   fprintf(f_output, "TEL;TYPE=work,voice:%s\n",       pst_rfc2426_escape(contact->business_phone2.str));
+    if (contact->car_phone.str)         fprintf(f_output, "TEL;TYPE=car,voice:%s\n",        pst_rfc2426_escape(contact->car_phone.str));
+    if (contact->home_fax.str)          fprintf(f_output, "TEL;TYPE=home,fax:%s\n",         pst_rfc2426_escape(contact->home_fax.str));
+    if (contact->home_phone.str)        fprintf(f_output, "TEL;TYPE=home,voice:%s\n",       pst_rfc2426_escape(contact->home_phone.str));
+    if (contact->home_phone2.str)       fprintf(f_output, "TEL;TYPE=home,voice:%s\n",       pst_rfc2426_escape(contact->home_phone2.str));
+    if (contact->isdn_phone.str)        fprintf(f_output, "TEL;TYPE=isdn:%s\n",             pst_rfc2426_escape(contact->isdn_phone.str));
+    if (contact->mobile_phone.str)      fprintf(f_output, "TEL;TYPE=cell,voice:%s\n",       pst_rfc2426_escape(contact->mobile_phone.str));
+    if (contact->other_phone.str)       fprintf(f_output, "TEL;TYPE=msg:%s\n",              pst_rfc2426_escape(contact->other_phone.str));
+    if (contact->pager_phone.str)       fprintf(f_output, "TEL;TYPE=pager:%s\n",            pst_rfc2426_escape(contact->pager_phone.str));
+    if (contact->primary_fax.str)       fprintf(f_output, "TEL;TYPE=fax,pref:%s\n",         pst_rfc2426_escape(contact->primary_fax.str));
+    if (contact->primary_phone.str)     fprintf(f_output, "TEL;TYPE=phone,pref:%s\n",       pst_rfc2426_escape(contact->primary_phone.str));
+    if (contact->radio_phone.str)       fprintf(f_output, "TEL;TYPE=pcs:%s\n",              pst_rfc2426_escape(contact->radio_phone.str));
+    if (contact->telex.str)             fprintf(f_output, "TEL;TYPE=bbs:%s\n",              pst_rfc2426_escape(contact->telex.str));
+    if (contact->job_title.str)         fprintf(f_output, "TITLE:%s\n",                     pst_rfc2426_escape(contact->job_title.str));
+    if (contact->profession.str)        fprintf(f_output, "ROLE:%s\n",                      pst_rfc2426_escape(contact->profession.str));
+    if (contact->assistant_name.str || contact->assistant_phone.str) {
         fprintf(f_output, "AGENT:BEGIN:VCARD\n");
-        if (contact->assistant_name)    fprintf(f_output, "FN:%s\n",                    pst_rfc2426_escape(contact->assistant_name));
-        if (contact->assistant_phone)   fprintf(f_output, "TEL:%s\n",                   pst_rfc2426_escape(contact->assistant_phone));
+        if (contact->assistant_name.str)    fprintf(f_output, "FN:%s\n",                    pst_rfc2426_escape(contact->assistant_name.str));
+        if (contact->assistant_phone.str)   fprintf(f_output, "TEL:%s\n",                   pst_rfc2426_escape(contact->assistant_phone.str));
     }
-    if (contact->company_name)      fprintf(f_output, "ORG:%s\n",                       pst_rfc2426_escape(contact->company_name));
-    if (comment)                    fprintf(f_output, "NOTE:%s\n",                      pst_rfc2426_escape(comment));
+    if (contact->company_name.str)      fprintf(f_output, "ORG:%s\n",                       pst_rfc2426_escape(contact->company_name.str));
+    if (comment)                        fprintf(f_output, "NOTE:%s\n",                      pst_rfc2426_escape(comment));
 
     fprintf(f_output, "VERSION: 3.0\n");
     fprintf(f_output, "END:VCARD\n\n");
@@ -1430,31 +1472,29 @@
 }
 
 
-void write_appointment(FILE* f_output, pst_item_appointment* appointment,
-               pst_item_email* email, FILETIME* create_date, FILETIME* modify_date)
+void write_appointment(FILE* f_output, pst_item *item,  pst_item_appointment* appointment,
+                       FILETIME* create_date, FILETIME* modify_date)
 {
+    // make everything utf8
+    pst_convert_utf8_null(item, &item->subject);
+    pst_convert_utf8_null(item, &item->body);
+    pst_convert_utf8_null(item, &appointment->location);
+
     fprintf(f_output, "BEGIN:VEVENT\n");
     if (create_date)
-        fprintf(f_output, "CREATED:%s\n",
-            pst_rfc2445_datetime_format(create_date));
+        fprintf(f_output, "CREATED:%s\n",                 pst_rfc2445_datetime_format(create_date));
     if (modify_date)
-        fprintf(f_output, "LAST-MOD:%s\n",
-            pst_rfc2445_datetime_format(modify_date));
-    if (email && email->subject)
-        fprintf(f_output, "SUMMARY:%s\n",
-            pst_rfc2426_escape(email->subject->subj));
-    if (email && email->body)
-        fprintf(f_output, "DESCRIPTION:%s\n",
-            pst_rfc2426_escape(email->body));
+        fprintf(f_output, "LAST-MOD:%s\n",                pst_rfc2445_datetime_format(modify_date));
+    if (item->subject.str)
+        fprintf(f_output, "SUMMARY:%s\n",                 pst_rfc2426_escape(item->subject.str));
+    if (item->body.str)
+        fprintf(f_output, "DESCRIPTION:%s\n",             pst_rfc2426_escape(item->body.str));
     if (appointment && appointment->start)
-        fprintf(f_output, "DTSTART;VALUE=DATE-TIME:%s\n",
-            pst_rfc2445_datetime_format(appointment->start));
+        fprintf(f_output, "DTSTART;VALUE=DATE-TIME:%s\n", pst_rfc2445_datetime_format(appointment->start));
     if (appointment && appointment->end)
-        fprintf(f_output, "DTEND;VALUE=DATE-TIME:%s\n",
-            pst_rfc2445_datetime_format(appointment->end));
-    if (appointment && appointment->location)
-        fprintf(f_output, "LOCATION:%s\n",
-            pst_rfc2426_escape(appointment->location));
+        fprintf(f_output, "DTEND;VALUE=DATE-TIME:%s\n",   pst_rfc2445_datetime_format(appointment->end));
+    if (appointment && appointment->location.str)
+        fprintf(f_output, "LOCATION:%s\n",                pst_rfc2426_escape(appointment->location.str));
     if (appointment) {
         switch (appointment->showas) {
             case PST_FREEBUSY_TENTATIVE:
@@ -1510,6 +1550,7 @@
 
 void create_enter_dir(struct file_ll* f, pst_item *item)
 {
+    pst_convert_utf8(item, &item->file_as);
     f->email_count  = 0;
     f->skip_count   = 0;
     f->type         = item->type;
@@ -1517,22 +1558,22 @@
 
     DEBUG_ENT("create_enter_dir");
     if (mode == MODE_KMAIL)
-        f->name = mk_kmail_dir(item->file_as); //create directory and form filename
+        f->name = mk_kmail_dir(item->file_as.str); //create directory and form filename
     else if (mode == MODE_RECURSE)
-        f->name = mk_recurse_dir(item->file_as);
+        f->name = mk_recurse_dir(item->file_as.str);
     else if (mode == MODE_SEPARATE) {
         // do similar stuff to recurse here.
-        mk_separate_dir(item->file_as);
+        mk_separate_dir(item->file_as.str);
         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(item->file_as)+strlen(OUTPUT_TEMPLATE)+1);
-        sprintf(f->name, OUTPUT_TEMPLATE, item->file_as);
+        f->name = (char*) xmalloc(strlen(item->file_as.str)+strlen(OUTPUT_TEMPLATE)+1);
+        sprintf(f->name, OUTPUT_TEMPLATE, item->file_as.str);
     }
 
-    f->dname = (char*) xmalloc(strlen(item->file_as)+1);
-    strcpy(f->dname, item->file_as);
+    f->dname = (char*) xmalloc(strlen(item->file_as.str)+1);
+    strcpy(f->dname, item->file_as.str);
 
     if (overwrite != 1) {
         int x = 0;
@@ -1559,7 +1600,7 @@
         }
     }
 
-    DEBUG_MAIN(("f->name = %s\nitem->folder_name = %s\n", f->name, item->file_as));
+    DEBUG_MAIN(("f->name = %s\nitem->folder_name = %s\n", f->name, item->file_as.str));
     if (mode != MODE_SEPARATE) {
         check_filename(f->name);
         if (!(f->output = fopen(f->name, "w"))) {
--- a/src/vbuf.c	Thu Mar 05 08:23:32 2009 -0800
+++ b/src/vbuf.c	Sun Mar 08 14:35:26 2009 -0700
@@ -43,16 +43,18 @@
 static int unicode_up = 0;
 static iconv_t i16to8;
 static const char *target_charset = NULL;
-static int         target_open = 0;
-static iconv_t    i8totarget;
+static int         target_open_from = 0;
+static int         target_open_to   = 0;
+static iconv_t     i8totarget = (iconv_t)-1;
+static iconv_t     target2i8  = (iconv_t)-1;
 
 
 void unicode_init()
 {
     if (unicode_up) unicode_close();
-    i16to8 = iconv_open("UTF-8", "UTF-16LE");
+    i16to8 = iconv_open("utf-8", "utf-16le");
     if (i16to8 == (iconv_t)-1) {
-        fprintf(stderr, "Couldn't open iconv descriptor for UTF-16LE to UTF-8.\n");
+        WARN(("Couldn't open iconv descriptor for utf-16le to utf-8.\n"));
         exit(1);
     }
     unicode_up = 1;
@@ -62,12 +64,12 @@
 void unicode_close()
 {
     iconv_close(i16to8);
-    if (target_open) {
-        iconv_close(i8totarget);
-        free((char *)target_charset);
-        target_charset = NULL;
-        target_open    = 0;
-    }
+    if (target_open_from) iconv_close(i8totarget);
+    if (target_open_to)   iconv_close(target2i8);
+    if (target_charset)   free((char *)target_charset);
+    target_charset   = NULL;
+    target_open_from = 0;
+    target_open_to   = 0;
     unicode_up = 0;
 }
 
@@ -125,39 +127,47 @@
 }
 
 
-size_t vb_utf8to8bit(vbuf *dest, const char *inbuf, int iblen, const char* charset)
+static void open_targets(const char* charset);
+static void open_targets(const char* charset)
+{
+    if (!target_charset || strcasecmp(target_charset, charset)) {
+        if (target_open_from) iconv_close(i8totarget);
+        if (target_open_to)   iconv_close(target2i8);
+        if (target_charset)   free((char *)target_charset);
+        target_charset   = strdup(charset);
+        target_open_from = 1;
+        target_open_to   = 1;
+        i8totarget = iconv_open(target_charset, "utf-8");
+        if (i8totarget == (iconv_t)-1) {
+            target_open_from = 0;
+            WARN(("Couldn't open iconv descriptor for utf-8 to %s.\n", target_charset));
+        }
+        target2i8 = iconv_open("utf-8", target_charset);
+        if (target2i8 == (iconv_t)-1) {
+            target_open_to = 0;
+            WARN(("Couldn't open iconv descriptor for %s to utf-8.\n", target_charset));
+        }
+    }
+}
+
+
+static size_t sbcs_conversion(vbuf *dest, const char *inbuf, int iblen, iconv_t conversion);
+static size_t sbcs_conversion(vbuf *dest, const char *inbuf, int iblen, iconv_t conversion)
 {
     size_t inbytesleft  = iblen;
     size_t icresult     = (size_t)-1;
     size_t outbytesleft = 0;
     char *outbuf        = NULL;
 
-    if (!target_charset || strcasecmp(target_charset, charset)) {
-        if (target_open) {
-            iconv_close(i8totarget);
-            free((char *)target_charset);
-        }
-        target_charset = strdup(charset);
-        target_open    = 1;
-        i8totarget = iconv_open(target_charset, "UTF-8");
-        if (i8totarget == (iconv_t)-1) {
-            target_open = 0;
-            fprintf(stderr, "Couldn't open iconv descriptor for UTF-8 to %s.\n", target_charset);
-            return (size_t)-1;
-        }
-    }
-
-    if (!target_open) return (size_t)-1;    // previous failure to open the target
-
-    if (2 > dest->blen) vbresize(dest, 2);
+    vbresize(dest, 2*iblen);
     dest->dlen = 0;
 
     do {
         outbytesleft = dest->blen - dest->dlen;
         outbuf = dest->b + dest->dlen;
-        icresult = iconv(i8totarget, (ICONV_CONST char**)&inbuf, &inbytesleft, &outbuf, &outbytesleft);
+        icresult = iconv(conversion, (ICONV_CONST char**)&inbuf, &inbytesleft, &outbuf, &outbytesleft);
         dest->dlen = outbuf - dest->b;
-        vbgrow(dest, 20);
+        if (inbytesleft) vbgrow(dest, 2*inbytesleft);
     } while ((size_t)-1 == icresult && E2BIG == errno);
 
     if (icresult == (size_t)-1) {
@@ -169,6 +179,22 @@
 }
 
 
+size_t vb_utf8to8bit(vbuf *dest, const char *inbuf, int iblen, const char* charset)
+{
+    open_targets(charset);
+    if (!target_open_from) return (size_t)-1;   // failure to open the target
+    return sbcs_conversion(dest, inbuf, iblen, i8totarget);
+}
+
+
+size_t vb_8bit2utf8(vbuf *dest, const char *inbuf, int iblen, const char* charset)
+{
+    open_targets(charset);
+    if (!target_open_to) return (size_t)-1;     // failure to open the target
+    return sbcs_conversion(dest, inbuf, iblen, target2i8);
+}
+
+
 vbuf *vballoc(size_t len)
 {
     struct varbuf *result = malloc(sizeof(struct varbuf));
@@ -226,20 +252,6 @@
 }
 
 
-//void vbdump( vbuf *vb ) // TODO: to stdout?  Yuck
-//{
-//      printf("vb dump-------------\n");
-//        printf("dlen: %d\n", vb->dlen );
-//      printf("blen: %d\n", vb->blen );
-//      printf("b - buf: %d\n", vb->b - vb->buf );
-//      printf("buf:\n");
-//      hexdump( vb->buf, 0, vb->blen, 1 );
-//      printf("b:\n");
-//      hexdump( vb->b, 0, vb->dlen, 1 );
-//      printf("^^^^^^^^^^^^^^^^^^^^\n");
-//}
-
-
 void vbgrow(struct varbuf *vb, size_t len)      // out: vbavail(vb) >= len, data are preserved
 {
     if (0 == len)
--- a/src/vbuf.h	Thu Mar 05 08:23:32 2009 -0800
+++ b/src/vbuf.h	Sun Mar 08 14:35:26 2009 -0700
@@ -88,6 +88,7 @@
 void unicode_close();
 size_t vb_utf16to8(vbuf *dest, const char *inbuf, int iblen);
 size_t vb_utf8to8bit(vbuf *dest, const char *inbuf, int iblen, const char* charset);
+size_t vb_8bit2utf8(vbuf *dest, const char *inbuf, int iblen, const char* charset);
 
 int vb_skipline( struct varbuf *vb ); // in: vb->b == "stuff\nmore_stuff"; out: vb->b == "more_stuff"