changeset 167:40e9de445038

improve consistency checking when fetching items from the pst file. avoid putting mixed item types into the same output folder.
author Carl Byington <carl@five-ten-sg.com>
date Wed, 18 Mar 2009 22:31:18 -0700
parents 55d4f17a35f2
children c1a2fd06ffe6
files ChangeLog configure.in regression/regression-tests.bash src/Makefile.am src/libpst.c src/libpst.h src/lspst.c src/pst2dii.cpp.in src/readpst.c
diffstat 9 files changed, 330 insertions(+), 250 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Mar 17 12:14:43 2009 -0700
+++ b/ChangeLog	Wed Mar 18 22:31:18 2009 -0700
@@ -1,3 +1,8 @@
+LibPST 0.6.34 (2009-0x-xx)
+===============================
+    * improve consistency checking when fetching items from the pst file.
+    * avoid putting mixed item types into the same output folder.
+
 LibPST 0.6.33 (2009-03-17)
 ===============================
 
--- a/configure.in	Tue Mar 17 12:14:43 2009 -0700
+++ b/configure.in	Wed Mar 18 22:31:18 2009 -0700
@@ -1,5 +1,5 @@
 AC_PREREQ(2.59)
-AC_INIT(libpst,0.6.33,carl@five-ten-sg.com)
+AC_INIT(libpst,0.6.34,carl@five-ten-sg.com)
 AC_CONFIG_SRCDIR([src/libpst.c])
 AC_CONFIG_HEADER([config.h])
 AM_INIT_AUTOMAKE
--- a/regression/regression-tests.bash	Tue Mar 17 12:14:43 2009 -0700
+++ b/regression/regression-tests.bash	Wed Mar 18 22:31:18 2009 -0700
@@ -38,7 +38,7 @@
     mkdir output$n
     #    ../src/readpst -cv -o output$n $fn >$ba.err 2>&1
     #           readpst -cv -o output$n -d dumper $fn >$ba.err 2>&1
-    $val ../src/readpst -S -cv -o output$n -d dumper $fn >$ba.err 2>&1
+    $val ../src/readpst -r -D -cv -o output$n -d dumper $fn >$ba.err 2>&1
          ../src/readpstlog -f I dumper >$ba.log
 
     #../src/getidblock -d -p $fn 0 >$ba.fulldump
@@ -50,7 +50,7 @@
 
 
 val="valgrind --leak-check=full"
-val=''
+#val=''
 
 pushd ..
 make || exit
@@ -84,7 +84,7 @@
     #doldif  18 test-mac.pst
     #doldif  19 harris.pst
 else
-    dopst  20 spam.pst
+    dopst  11 flow.pst
     exit
     dopst   1 ams.pst
     dopst   2 sample_64.pst
@@ -96,7 +96,6 @@
     dopst   8 ol2k3high.pst
     dopst   9 ol97high.pst
     dopst  10 returned_message.pst
-    dopst  11 flow.pst
     dopst  12 test-html.pst
     dopst  13 test-text.pst
     dopst  14 joe.romanowski.pst
@@ -105,6 +104,8 @@
     #dopst  17 hourig3.pst
     dopst  18 test-mac.pst
     dopst  19 harris.pst
+    dopst  20 spam.pst
 fi
 
 grep 'lost:' *err | grep -v 'lost: 0 '
+grep 'should have been' *err
--- a/src/Makefile.am	Tue Mar 17 12:14:43 2009 -0700
+++ b/src/Makefile.am	Wed Mar 18 22:31:18 2009 -0700
@@ -74,7 +74,7 @@
         libstrfunc.h\
         timeconv.h  \
         vbuf.h
-    libpst_la_LDFLAGS     = $(NO_UNDEFINED) -version-info 1:2:0
+    libpst_la_LDFLAGS     = $(NO_UNDEFINED) -version-info 1:3:0
 endif
 
 libpst_la_SOURCES     = $(common_source) $(common_header)
--- a/src/libpst.c	Tue Mar 17 12:14:43 2009 -0700
+++ b/src/libpst.c	Wed Mar 18 22:31:18 2009 -0700
@@ -417,9 +417,9 @@
             DEBUG_WARN(("Couldn't find ID pointer. Cannot handle attachment\n"));
             size = 0;
         }
-        attach->size = size;
+        attach->data.size = size;
     } else {
-        size = attach->size;
+        size = attach->data.size;
     }
     DEBUG_RET();
     return size;
@@ -438,11 +438,11 @@
         } else {
             DEBUG_WARN(("Couldn't find ID pointer. Cannot save attachment to file\n"));
         }
-        attach->size = size;
+        attach->data.size = size;
     } else {
         // save the attachment to the file
-        size = attach->size;
-        (void)pst_fwrite(attach->data, (size_t)1, size, fp);
+        size = attach->data.size;
+        (void)pst_fwrite(attach->data.data, (size_t)1, size, fp);
     }
     DEBUG_RET();
     return size;
@@ -461,15 +461,15 @@
         } else {
             DEBUG_WARN(("Couldn't find ID pointer. Cannot save attachment to Base64\n"));
         }
-        attach->size = size;
+        attach->data.size = size;
     } else {
         // encode the attachment to the file
-        char *c = base64_encode(attach->data, attach->size);
+        char *c = base64_encode(attach->data.data, attach->data.size);
         if (c) {
             (void)pst_fwrite(c, (size_t)1, strlen(c), fp);
             free(c);    // caught by valgrind
         }
-        size = attach->size;
+        size = attach->data.size;
     }
     DEBUG_RET();
     return size;
@@ -1711,6 +1711,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)
+#define SAFE_FREE_BIN(x) SAFE_FREE(x.data)
 
 // 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)        );} }
@@ -1721,20 +1722,38 @@
 #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) {                                 \
+#define LIST_COPY(targ, type) {                                    \
     targ = type realloc(targ, list->elements[x]->size+1);          \
-    memcpy(targ, list->elements[x]->data, list->elements[x]->size);   \
+    memcpy(targ, list->elements[x]->data, list->elements[x]->size);\
     memset(((char*)targ)+list->elements[x]->size, 0, (size_t)1);   \
 }
 
-#define LIST_COPY_BOOL(label, targ) {                           \
-    if (*(int16_t*)list->elements[x]->data) {                      \
-        DEBUG_EMAIL((label" - True\n"));                        \
-        targ = 1;                                               \
-    } else {                                                    \
-        DEBUG_EMAIL((label" - False\n"));                       \
-        targ = 0;                                               \
-    }                                                           \
+#define LIST_COPY_CSTR(targ) {                                              \
+    if ((list->elements[x]->type == 0x1f) ||                                \
+        (list->elements[x]->type == 0x1e) ||                                \
+        (list->elements[x]->type == 0x102)) {                               \
+        LIST_COPY(targ, (char*))                                            \
+    }                                                                       \
+    else {                                                                  \
+        DEBUG_EMAIL(("src not 0x1e or 0x1f or 0x102 for string dst\n"));    \
+        DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);    \
+        SAFE_FREE(targ);                                                    \
+        targ = NULL;                                                        \
+    }                                                                       \
+}
+
+#define LIST_COPY_BOOL(label, targ) {                                       \
+    if (list->elements[x]->type != 0x0b) {                                  \
+        DEBUG_EMAIL(("src not 0x0b for boolean dst\n"));                    \
+        DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);    \
+    }                                                                       \
+    if (*(int16_t*)list->elements[x]->data) {                               \
+        DEBUG_EMAIL((label" - True\n"));                                    \
+        targ = 1;                                                           \
+    } else {                                                                \
+        DEBUG_EMAIL((label" - False\n"));                                   \
+        targ = 0;                                                           \
+    }                                                                       \
 }
 
 #define LIST_COPY_EMAIL_BOOL(label, targ) {                     \
@@ -1752,23 +1771,31 @@
     LIST_COPY_BOOL(label, targ)                                 \
 }
 
-#define LIST_COPY_INT16_N(label, targ) {                        \
-    memcpy(&(targ), list->elements[x]->data, sizeof(targ));        \
-    LE16_CPU(targ);                                             \
+#define LIST_COPY_INT16_N(targ) {                                           \
+    if (list->elements[x]->type != 0x02) {                                  \
+        DEBUG_EMAIL(("src not 0x02 for int16 dst\n"));                      \
+        DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);    \
+    }                                                                       \
+    memcpy(&(targ), list->elements[x]->data, sizeof(targ));                 \
+    LE16_CPU(targ);                                                         \
 }
 
 #define LIST_COPY_INT16(label, targ) {                          \
-    LIST_COPY_INT16_N(label, targ);                             \
+    LIST_COPY_INT16_N(targ);                                    \
     DEBUG_EMAIL((label" - %i %#x\n", (int)targ, (int)targ));    \
 }
 
-#define LIST_COPY_INT32_N(label, targ) {                        \
-    memcpy(&(targ), list->elements[x]->data, sizeof(targ));        \
-    LE32_CPU(targ);                                             \
+#define LIST_COPY_INT32_N(targ) {                                           \
+    if (list->elements[x]->type != 0x03) {                                  \
+        DEBUG_EMAIL(("src not 0x03 for int32 dst\n"));                      \
+        DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);    \
+    }                                                                       \
+    memcpy(&(targ), list->elements[x]->data, sizeof(targ));                 \
+    LE32_CPU(targ);                                                         \
 }
 
 #define LIST_COPY_INT32(label, targ) {                          \
-    LIST_COPY_INT32_N(label, targ);                             \
+    LIST_COPY_INT32_N(targ);                                    \
     DEBUG_EMAIL((label" - %i %#x\n", (int)targ, (int)targ));    \
 }
 
@@ -1794,7 +1821,7 @@
 
 #define LIST_COPY_ENUM(label, targ, delta, count, ...) {        \
     char *tlabels[] = {__VA_ARGS__};                            \
-    LIST_COPY_INT32_N(label, targ);                             \
+    LIST_COPY_INT32_N(targ);                                    \
     targ += delta;                                              \
     DEBUG_EMAIL((label" - %s [%i]\n",                           \
         (((int)targ < 0) || ((int)targ >= count))               \
@@ -1814,7 +1841,7 @@
 
 #define LIST_COPY_ENUM16(label, targ, delta, count, ...) {      \
     char *tlabels[] = {__VA_ARGS__};                            \
-    LIST_COPY_INT16_N(label, targ);                             \
+    LIST_COPY_INT16_N(targ);                                    \
     targ += delta;                                              \
     DEBUG_EMAIL((label" - %s [%i]\n",                           \
         (((int)targ < 0) || ((int)targ >= count))               \
@@ -1828,7 +1855,6 @@
 }
 
 #define LIST_COPY_ENTRYID(label, targ) {                        \
-    MALLOC_MESSAGESTORE(item);                                  \
     LIST_COPY(targ, (pst_entryid*));                            \
     LE32_CPU(targ->u1);                                         \
     LE32_CPU(targ->id);                                         \
@@ -1849,8 +1875,8 @@
 // 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->elements[x]->type == 0x1f) ? 1 : 0;              \
+    LIST_COPY_CSTR(targ.str);                                           \
+    targ.is_utf8 = (list->elements[x]->type == 0x1f) ? 1 : 0;           \
     DEBUG_EMAIL((label" - unicode %d - %s\n", targ.is_utf8, targ.str)); \
 }
 
@@ -1875,12 +1901,16 @@
 }
 
 // malloc space and copy the item filetime
-#define LIST_COPY_TIME(label, targ) {                           \
-    targ = (FILETIME*) realloc(targ, sizeof(FILETIME));         \
-    memcpy(targ, list->elements[x]->data, list->elements[x]->size);   \
-    LE32_CPU(targ->dwLowDateTime);                              \
-    LE32_CPU(targ->dwHighDateTime);                             \
-    DEBUG_EMAIL((label" - %s", fileTimeToAscii(targ)));         \
+#define LIST_COPY_TIME(label, targ) {                                       \
+    if (list->elements[x]->type != 0x40) {                                  \
+        DEBUG_EMAIL(("src not 0x40 for filetime dst\n"));                   \
+        DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);    \
+    }                                                                       \
+    targ = (FILETIME*) realloc(targ, sizeof(FILETIME));                     \
+    memcpy(targ, list->elements[x]->data, list->elements[x]->size);         \
+    LE32_CPU(targ->dwLowDateTime);                                          \
+    LE32_CPU(targ->dwHighDateTime);                                         \
+    DEBUG_EMAIL((label" - %s", fileTimeToAscii(targ)));                     \
 }
 
 #define LIST_COPY_EMAIL_TIME(label, targ) {                     \
@@ -1904,21 +1934,21 @@
 }
 
 // malloc space and copy the current item's data and size
-#define LIST_COPY_SIZE(targ, type, mysize) {        \
-    mysize = list->elements[x]->size;                  \
-    if (mysize) {                                   \
-        targ = type realloc(targ, mysize);          \
-        memcpy(targ, list->elements[x]->data, mysize); \
-    }                                               \
-    else {                                          \
-        SAFE_FREE(targ);                            \
-        targ = NULL;                                \
-    }                                               \
+#define LIST_COPY_BIN(targ) {                                       \
+    targ.size = list->elements[x]->size;                            \
+    if (targ.size) {                                                \
+        targ.data = (char*)realloc(targ.data, targ.size);           \
+        memcpy(targ.data, list->elements[x]->data, targ.size);      \
+    }                                                               \
+    else {                                                          \
+        SAFE_FREE_BIN(targ);                                        \
+        targ.data = NULL;                                           \
+    }                                                               \
 }
 
-#define LIST_COPY_EMAIL_SIZE(label, targ, mysize) { \
+#define LIST_COPY_EMAIL_BIN(label, targ) {          \
     MALLOC_EMAIL(item);                             \
-    LIST_COPY_SIZE(targ, (char*), mysize);          \
+    LIST_COPY_BIN(targ);                            \
     DEBUG_EMAIL((label"\n"));                       \
 }
 
@@ -1957,12 +1987,14 @@
 
             switch (list->elements[x]->mapi_id) {
                 case PST_ATTRIB_HEADER: // CUSTOM attribute for saying the Extra Headers
-                    if (list->elements[x]->extra) {
+                    if ((list->elements[x]->extra) &&
+                        ((list->elements[x]->type == 0x1f)  ||
+                         (list->elements[x]->type == 0x1e))) {
                         ef = (pst_item_extra_field*) xmalloc(sizeof(pst_item_extra_field));
                         memset(ef, 0, sizeof(pst_item_extra_field));
                         ef->field_name = (char*) xmalloc(strlen(list->elements[x]->extra)+1);
                         strcpy(ef->field_name, list->elements[x]->extra);
-                        LIST_COPY(ef->value, (char*));
+                        LIST_COPY_CSTR(ef->value);
                         ef->next = item->extra_fields;
                         item->extra_fields = ef;
                         DEBUG_EMAIL(("Extra Field - \"%s\" = \"%s\"\n", ef->field_name, ef->value));
@@ -1984,13 +2016,19 @@
                         }
                     }
                     else {
-                        DEBUG_EMAIL(("NULL extra field\n"));
+                        DEBUG_EMAIL(("What does this mean?\n"));
+                        DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
                     }
                     break;
                 case 0x0002: // PR_ALTERNATE_RECIPIENT_ALLOWED
-                    // If set to true, the sender allows this email to be autoforwarded
-                    LIST_COPY_EMAIL_BOOL("AutoForward allowed", item->email->autoforward);
-                    if (!item->email->autoforward) item->email->autoforward = -1;
+                    if (list->elements[x]->type == 0x0b) {
+                        // If set to true, the sender allows this email to be autoforwarded
+                        LIST_COPY_EMAIL_BOOL("AutoForward allowed", item->email->autoforward);
+                        if (!item->email->autoforward) item->email->autoforward = -1;
+                    } else {
+                        DEBUG_EMAIL(("What does this mean?\n"));
+                        DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
+                    }
                     break;
                 case 0x0003: // Extended Attributes table
                     DEBUG_EMAIL(("Extended Attributes Table - NOT PROCESSED\n"));
@@ -1999,28 +2037,49 @@
                     LIST_COPY_EMAIL_ENUM("Importance Level", item->email->importance, 0, 3, "Low", "Normal", "High");
                     break;
                 case 0x001A: // PR_MESSAGE_CLASS IPM.x
-                    LIST_COPY(item->ascii_type, (char*));
-                    if (pst_strincmp("IPM.Note", item->ascii_type, 8) == 0)
-                        item->type = PST_TYPE_NOTE;
-                    else if (pst_stricmp("IPM", item->ascii_type) == 0)
-                        item->type = PST_TYPE_NOTE;
-                    else if (pst_strincmp("IPM.Contact", item->ascii_type, 11) == 0)
-                        item->type = PST_TYPE_CONTACT;
-                    else if (pst_strincmp("REPORT.IPM.Note", item->ascii_type, 15) == 0)
-                        item->type = PST_TYPE_REPORT;
-                    else if (pst_strincmp("IPM.Activity", item->ascii_type, 12) == 0)
-                        item->type = PST_TYPE_JOURNAL;
-                    else if (pst_strincmp("IPM.Appointment", item->ascii_type, 15) == 0)
-                        item->type = PST_TYPE_APPOINTMENT;
-                    else if (pst_strincmp("IPM.Task", item->ascii_type, 8) == 0)
-                        item->type = PST_TYPE_TASK;
-                    else
-                        item->type = PST_TYPE_OTHER;
-                    DEBUG_EMAIL(("Message class %s [%"PRIi32"] \n", item->ascii_type, item->type));
+                    if ((list->elements[x]->type == 0x1e) ||
+                        (list->elements[x]->type == 0x1e)) {
+                        LIST_COPY_CSTR(item->ascii_type);
+                        if (!item->ascii_type) item->ascii_type = strdup("unknown");
+                        if (pst_strincmp("IPM.Note", item->ascii_type, 8) == 0)
+                            item->type = PST_TYPE_NOTE;
+                        else if (pst_stricmp("IPM", item->ascii_type) == 0)
+                            item->type = PST_TYPE_NOTE;
+                        else if (pst_strincmp("IPM.Contact", item->ascii_type, 11) == 0)
+                            item->type = PST_TYPE_CONTACT;
+                        else if (pst_strincmp("REPORT.IPM.Note", item->ascii_type, 15) == 0)
+                            item->type = PST_TYPE_REPORT;
+                        else if (pst_strincmp("IPM.Activity", item->ascii_type, 12) == 0)
+                            item->type = PST_TYPE_JOURNAL;
+                        else if (pst_strincmp("IPM.Appointment", item->ascii_type, 15) == 0)
+                            item->type = PST_TYPE_APPOINTMENT;
+                        //else if (pst_strincmp("IPM.Schedule.Meeting", item->ascii_type, 20) == 0)
+                        //    item->type = PST_TYPE_APPOINTMENT;
+                        // these seem to be appointments, but they are inside the email folder,
+                        // and unless we are in separate mode, we would dump an appointment
+                        // into the middle of a mailbox file.
+                        else if (pst_strincmp("IPM.StickyNote", item->ascii_type, 14) == 0)
+                            item->type = PST_TYPE_STICKYNOTE;
+                        else if (pst_strincmp("IPM.Task", item->ascii_type, 8) == 0)
+                            item->type = PST_TYPE_TASK;
+                        else
+                            item->type = PST_TYPE_OTHER;
+                        DEBUG_EMAIL(("Message class %s [%"PRIi32"] \n", item->ascii_type, item->type));
+                    }
+                    else {
+                        DEBUG_EMAIL(("What does this mean?\n"));
+                        DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
+                    }
                     break;
                 case 0x0023: // PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED
-                    // set if the sender wants a delivery report from all recipients
-                    LIST_COPY_EMAIL_BOOL("Global Delivery Report", item->email->delivery_report);
+                    if (list->elements[x]->type == 0x0b) {
+                        // set if the sender wants a delivery report from all recipients
+                        LIST_COPY_EMAIL_BOOL("Global Delivery Report", item->email->delivery_report);
+                    }
+                    else {
+                        DEBUG_EMAIL(("What does this mean?\n"));
+                        DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
+                    }
                     break;
                 case 0x0026: // PR_PRIORITY
                     LIST_COPY_EMAIL_ENUM("Priority", item->email->priority, 1, 3, "NonUrgent", "Normal", "Urgent");
@@ -2116,7 +2175,7 @@
                     LIST_COPY_EMAIL_STR("Processed Subject (Conversation Topic)", item->email->processed_subject);
                     break;
                 case 0x0071: // PR_CONVERSATION_INDEX
-                    LIST_COPY_EMAIL_INT32("Conversation Index", item->email->conversation_index);
+                    LIST_COPY_EMAIL_BIN("Conversation Index", item->email->conversation_index);
                     break;
                 case 0x0072: // PR_ORIGINAL_DISPLAY_BCC
                     LIST_COPY_EMAIL_STR("Original display bcc", item->email->original_bcc);
@@ -2208,17 +2267,14 @@
                     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 - "));
                     NULL_CHECK(attach);
                     LIST_COPY_INT32("Attachment Size", t);
-                    attach->size = (size_t)t;
+                    attach->data.size = (size_t)t;
                     break;
                 case 0x0FF9: // PR_RECORD_KEY Record Header 1
-                    DEBUG_EMAIL(("Record Key 1 - "));
-                    LIST_COPY(item->record_key, (char*));
-                    item->record_key_size = list->elements[x]->size;
-                    DEBUG_EMAIL_HEXPRINT(item->record_key, item->record_key_size);
-                    DEBUG_EMAIL(("\n"));
+                    LIST_COPY_BIN(item->record_key);
+                    DEBUG_EMAIL(("Record Key\n"));
+                    DEBUG_EMAIL_HEXPRINT(item->record_key.data, item->record_key.size);
                     break;
                 case 0x1000: // PR_BODY
                     LIST_COPY_STR("Plain Text body", item->body);
@@ -2240,7 +2296,7 @@
                     LIST_COPY_EMAIL_STR("RTF Sync body tag", item->email->rtf_body_tag);
                     break;
                 case 0x1009: // PR_RTF_COMPRESSED - rtf data is lzw compressed
-                    LIST_COPY_EMAIL_SIZE("RTF Compressed body", item->email->rtf_compressed, item->email->rtf_compressed_size);
+                    LIST_COPY_EMAIL_BIN("RTF Compressed body", item->email->rtf_compressed);
                     break;
                 case 0x1010: // PR_RTF_SYNC_PREFIX_COUNT
                     // a count of the ignored characters before the first significant character
@@ -2308,17 +2364,17 @@
                     LIST_COPY_STORE_ENTRYID("Search Root Folder record", item->message_store->search_root_folder);
                     break;
                 case 0x3602: // PR_CONTENT_COUNT Number of emails stored in a folder
-                    LIST_COPY_FOLDER_INT32("Folder Email Count", item->folder->email_count);
+                    LIST_COPY_FOLDER_INT32("Folder Email Count", item->folder->item_count);
                     break;
                 case 0x3603: // PR_CONTENT_UNREAD Number of unread emails
-                    LIST_COPY_FOLDER_INT32("Unread Email Count", item->folder->unseen_email_count);
+                    LIST_COPY_FOLDER_INT32("Unread Email Count", item->folder->unseen_item_count);
                     break;
                 case 0x360A: // PR_SUBFOLDERS Has children
                     MALLOC_FOLDER(item);
                     LIST_COPY_BOOL("Has Subfolders", item->folder->subfolder);
                     break;
                 case 0x3613: // PR_CONTAINER_CLASS IPF.x
-                    LIST_COPY(item->ascii_type, (char*));
+                    LIST_COPY_CSTR(item->ascii_type);
                     if (pst_strincmp("IPF.Note", item->ascii_type, 8) == 0)
                         item->type = PST_TYPE_NOTE;
                     else if (pst_stricmp("IPF", item->ascii_type) == 0)
@@ -2348,12 +2404,9 @@
                     NULL_CHECK(attach);
                     if (!list->elements[x]->data) { //special case
                         attach->id2_val = list->elements[x]->type;
-                        DEBUG_EMAIL(("Seen a Reference. The data hasn't been loaded yet. [%#"PRIx64"][%#x]\n",
-                                 attach->id2_val, list->elements[x]->type));
+                        DEBUG_EMAIL(("Seen a Reference. The data hasn't been loaded yet. [%#"PRIx64"]\n", attach->id2_val));
                     } else {
-                        LIST_COPY(attach->data, (char*));
-                        attach->size = list->elements[x]->size;
-                        DEBUG_EMAIL(("NOT PRINTED\n"));
+                        LIST_COPY_BIN(attach->data);
                     }
                     break;
                 case 0x3704: // PR_ATTACH_FILENAME Attachment filename (8.3)
@@ -2635,13 +2688,10 @@
                 case 0x3FFD: // PR_MESSAGE_CODEPAGE
                     LIST_COPY_INT32("Message code page", item->message_codepage);
                     break;
-                case 0x65E3: // Entry ID?
-                    DEBUG_EMAIL(("Entry ID - "));
-                    item->record_key = (char*) xmalloc(16+1);
-                    memcpy(item->record_key, &(list->elements[x]->data[1]), 16); //skip first byte
-                    item->record_key[16]='\0';
-                    item->record_key_size=16;
-                    DEBUG_EMAIL_HEXPRINT((char*)item->record_key, 16);
+                case 0x65E3: // PR_PREDECESSOR_CHANGE_LIST
+                    LIST_COPY_BIN(item->predecessor_change);
+                    DEBUG_EMAIL(("Predecessor Change\n"));
+                    DEBUG_EMAIL_HEXPRINT(item->predecessor_change.data, item->predecessor_change.size);
                     break;
                 case 0x67F2: // ID2 value of the attachments proper record
                     DEBUG_EMAIL(("Attachment ID2 value - "));
@@ -2659,13 +2709,13 @@
                     LIST_COPY_STORE_INT32("Password checksum", item->message_store->pwd_chksum);
                     break;
                 case 0x6F02: // Secure HTML Body
-                    LIST_COPY_EMAIL_SIZE("Secure HTML Body", item->email->encrypted_htmlbody, item->email->encrypted_htmlbody_size);
+                    LIST_COPY_EMAIL_BIN("Secure HTML Body", item->email->encrypted_htmlbody);
                     break;
                 case 0x6F04: // Secure Text Body
-                    LIST_COPY_EMAIL_SIZE("Secure Text Body", item->email->encrypted_body, item->email->encrypted_body_size);
+                    LIST_COPY_EMAIL_BIN("Secure Text Body", item->email->encrypted_body);
                     break;
                 case 0x7C07: // top of folders ENTRYID
-                    LIST_COPY_ENTRYID("Top of folders RecID", item->message_store->top_of_folder);
+                    LIST_COPY_STORE_ENTRYID("Top of folders RecID", item->message_store->top_of_folder);
                     break;
                 case 0x8005: // Contact's Fullname
                     LIST_COPY_CONTACT_STR("Contact Fullname", item->contact->fullname);
@@ -2909,12 +2959,12 @@
                             list->elements[x]->size));
                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
 
-                    } else if (list->elements[x]->type == (uint32_t)0x101E) {
+                    } else if (list->elements[x]->type == (uint32_t)0x101e) {
                         DEBUG_EMAIL(("Unknown type %#x Array of Strings [size = %#x]\n", list->elements[x]->mapi_id,
                             list->elements[x]->size));
                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
 
-                    } else if (list->elements[x]->type == (uint32_t)0x101F) {
+                    } else if (list->elements[x]->type == (uint32_t)0x101f) {
                         DEBUG_EMAIL(("Unknown type %#x Array of Unicode Strings [size = %#x]\n", list->elements[x]->mapi_id,
                             list->elements[x]->size));
                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
@@ -3103,7 +3153,7 @@
         SAFE_FREE_STR(attach->filename1);
         SAFE_FREE_STR(attach->filename2);
         SAFE_FREE_STR(attach->mimetype);
-        SAFE_FREE(attach->data);
+        SAFE_FREE_BIN(attach->data);
         pst_free_id2(attach->id2_head);
         t = attach->next;
         free(attach);
@@ -3121,8 +3171,9 @@
             SAFE_FREE(item->email->arrival_date);
             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_BIN(item->email->conversation_index);
+            SAFE_FREE_BIN(item->email->encrypted_body);
+            SAFE_FREE_BIN(item->email->encrypted_htmlbody);
             SAFE_FREE_STR(item->email->header);
             SAFE_FREE_STR(item->email->htmlbody);
             SAFE_FREE_STR(item->email->in_reply_to);
@@ -3143,7 +3194,7 @@
             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_BIN(item->email->rtf_compressed);
             SAFE_FREE_STR(item->email->return_path_address);
             SAFE_FREE_STR(item->email->sender_access);
             SAFE_FREE_STR(item->email->sender_address);
@@ -3308,7 +3359,8 @@
         SAFE_FREE_STR(item->file_as);
         SAFE_FREE(item->modify_date);
         SAFE_FREE_STR(item->outlook_version);
-        SAFE_FREE(item->record_key);
+        SAFE_FREE_BIN(item->record_key);
+        SAFE_FREE_BIN(item->predecessor_change);
         free(item);
     }
     DEBUG_RET();
@@ -3784,7 +3836,7 @@
         DEBUG_RET();
         return 0;
     }
-    DEBUG_HEXDUMPC(buf3, a, 0x10);
+    DEBUG_HEXDUMPC(buf3, a, 16);
     memcpy(&block_hdr, buf3, sizeof(block_hdr));
     LE16_CPU(block_hdr.index_offset);
     LE16_CPU(block_hdr.type);
--- a/src/libpst.h	Tue Mar 17 12:14:43 2009 -0700
+++ b/src/libpst.h	Wed Mar 18 22:31:18 2009 -0700
@@ -172,6 +172,12 @@
 } pst_string;
 
 
+typedef struct pst_binary {
+    size_t  size;
+    char   *data;
+} pst_binary;
+
+
 /** This struct defines an email message
  */
 typedef struct pst_item_email {
@@ -180,17 +186,15 @@
     int         autoforward;
     pst_string  cc_address;
     pst_string  bcc_address;
-    int32_t     conversation_index;
+    pst_binary  conversation_index;
     /** 1 = true, 0 = false */
     int         conversion_prohibited;
     /** 1 = true, 0 = false */
     int         delete_after_submit;
     /** 1 = true, 0 = false */
     int         delivery_report;
-    char       *encrypted_body;
-    size_t      encrypted_body_size;
-    char       *encrypted_htmlbody;
-    size_t      encrypted_htmlbody_size;
+    pst_binary  encrypted_body;
+    pst_binary  encrypted_htmlbody;
     pst_string  header;
     pst_string  htmlbody;
     /** 0=low, 1=normal, 2=high */
@@ -230,8 +234,7 @@
     int32_t     rtf_body_char_count;
     int32_t     rtf_body_crc;
     pst_string  rtf_body_tag;
-    char       *rtf_compressed;
-    uint32_t    rtf_compressed_size;
+    pst_binary  rtf_compressed;
     /** 1 = true, 0 = false */
     int         rtf_in_sync;
     int32_t     rtf_ws_prefix_count;
@@ -256,8 +259,8 @@
 
 
 typedef struct pst_item_folder {
-    int32_t  email_count;
-    int32_t  unseen_email_count;
+    int32_t  item_count;
+    int32_t  unseen_item_count;
     int32_t  assoc_count;
     /** 1 = true, 0 = false */
     int      subfolder;
@@ -401,8 +404,7 @@
     pst_string  filename1;
     pst_string  filename2;
     pst_string  mimetype;
-    char       *data;
-    size_t      size;
+    pst_binary  data;
     uint64_t    id2_val;
     /** calculated from id2_val during creation of record */
     uint64_t    i_id;
@@ -506,8 +508,8 @@
     int32_t     message_codepage;
     int32_t     message_size;
     pst_string  outlook_version;
-    char       *record_key;             // probably 16 bytes long.
-    size_t      record_key_size;
+    pst_binary  record_key;
+    pst_binary  predecessor_change;     // was formerly stored in record_key
     /** 1 = true, 0 = false */
     int         response_requested;
     FILETIME   *create_date;
--- a/src/lspst.c	Tue Mar 17 12:14:43 2009 -0700
+++ b/src/lspst.c	Wed Mar 18 22:31:18 2009 -0700
@@ -11,7 +11,7 @@
 struct file_ll {
     char *dname;
     int32_t stored_count;
-    int32_t email_count;
+    int32_t item_count;
     int32_t skip_count;
     int32_t type;
 };
@@ -29,10 +29,10 @@
 void create_enter_dir(struct file_ll* f, pst_item *item)
 {
     pst_convert_utf8(item, &item->file_as);
-    f->email_count  = 0;
+    f->item_count   = 0;
     f->skip_count   = 0;
     f->type         = item->type;
-    f->stored_count = (item->folder) ? item->folder->email_count : 0;
+    f->stored_count = (item->folder) ? item->folder->item_count : 0;
     f->dname        = (char*) xmalloc(strlen(item->file_as.str)+1);
     strcpy(f->dname, item->file_as.str);
 }
--- a/src/pst2dii.cpp.in	Tue Mar 17 12:14:43 2009 -0700
+++ b/src/pst2dii.cpp.in	Wed Mar 18 22:31:18 2009 -0700
@@ -204,8 +204,8 @@
     if (!(fp = fopen(temp, "wb"))) {
         WARN(("write_separate_attachment: Cannot open attachment save file \"%s\"\n", temp));
     } else {
-        if (current_attach->data)
-            pst_fwrite(current_attach->data, 1, current_attach->size, fp);
+        if (current_attach->data.data)
+            pst_fwrite(current_attach->data.data, 1, current_attach->data.size, fp);
         else {
             (void)pst_attach_to_file(pst, current_attach, fp);
         }
@@ -559,7 +559,7 @@
     } 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) {
+    } else if (item->email->encrypted_body.data || item->email->encrypted_htmlbody.data) {
         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");
         print_pdf(ln);
@@ -569,8 +569,8 @@
     int attach_num = 0;
     for (pst_item_attach* current_attach = item->attach; current_attach; current_attach = current_attach->next) {
         DEBUG_EMAIL(("Attempting Attachment encoding\n"));
-        if (!current_attach->data) {
-            DEBUG_EMAIL(("Data of attachment is NULL!. Size is supposed to be %i\n", current_attach->size));
+        if (!current_attach->data.data) {
+            DEBUG_EMAIL(("Data of attachment is NULL!. Size is supposed to be %i\n", current_attach->data.size));
         }
         string an = write_separate_attachment(f.name, current_attach, ++attach_num, pst);
         fprintf(dii_file, "@EATTACH %s\n", an.c_str());
@@ -588,7 +588,7 @@
     f.email_count  = 0;
     f.skip_count   = 0;
     f.type         = item->type;
-    f.stored_count = (item->folder) ? item->folder->email_count : 0;
+    f.stored_count = (item->folder) ? item->folder->item_count : 0;
     f.name         = ((parent) ? parent->name + "/" : "") + string(item->file_as.str);
 }
 
--- a/src/readpst.c	Tue Mar 17 12:14:43 2009 -0700
+++ b/src/readpst.c	Wed Mar 18 22:31:18 2009 -0700
@@ -21,7 +21,7 @@
     char *dname;
     FILE * output;
     int32_t stored_count;
-    int32_t email_count;
+    int32_t item_count;
     int32_t skip_count;
     int32_t type;
 };
@@ -130,99 +130,120 @@
     memset(&ff, 0, sizeof(ff));
     create_enter_dir(&ff, outeritem);
 
-    while (d_ptr) {
+    for (; d_ptr; d_ptr = d_ptr->next) {
         DEBUG_MAIN(("main: New item record\n"));
         if (!d_ptr->desc) {
+            ff.skip_count++;
             DEBUG_WARN(("main: ERROR item's desc record is NULL\n"));
-            ff.skip_count++;
+            continue;
         }
-        else {
-            DEBUG_MAIN(("main: Desc Email ID %#"PRIx64" [d_ptr->d_id = %#"PRIx64"]\n", d_ptr->desc->i_id, d_ptr->d_id));
+        DEBUG_MAIN(("main: Desc Email ID %#"PRIx64" [d_ptr->d_id = %#"PRIx64"]\n", d_ptr->desc->i_id, d_ptr->d_id));
+
+        item = pst_parse_item(&pstfile, d_ptr, NULL);
+        DEBUG_MAIN(("main: About to process item\n"));
 
-            item = pst_parse_item(&pstfile, d_ptr, NULL);
-            DEBUG_MAIN(("main: About to process item\n"));
-            if (item && item->subject.str) {
-                DEBUG_EMAIL(("item->subject = %s\n", item->subject.str));
-            }
-            if (item) {
-                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.str);
-                    process(item, d_ptr->child);
+        if (!item) {
+            ff.skip_count++;
+            DEBUG_MAIN(("main: A NULL item was seen\n"));
+            continue;
+        }
+
+        if (item->subject.str) {
+            DEBUG_EMAIL(("item->subject = %s\n", item->subject.str));
+        }
 
-                } else if (item->contact && (item->type == PST_TYPE_CONTACT)) {
-                    if (mode == MODE_SEPARATE) mk_separate_file(&ff);
-                    ff.email_count++;
-                    DEBUG_MAIN(("main: Processing Contact\n"));
-                    if (ff.type != PST_TYPE_CONTACT) {
-                        DEBUG_MAIN(("main: I have a contact, but the folder type %"PRIi32" isn't a contacts folder. Processing anyway\n", ff.type));
-                    }
-                    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);
-                    }
+        if (item->folder && item->file_as.str) {
+            DEBUG_MAIN(("Processing Folder \"%s\"\n", item->file_as.str));
+            if (output_mode != OUTPUT_QUIET) printf("Processing Folder \"%s\"\n", item->file_as.str);
+            ff.item_count++;
+            if (d_ptr->child && (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
+                process(item, d_ptr->child);
+            }
 
-                } else if (item->email && (item->type == PST_TYPE_NOTE || item->type == PST_TYPE_REPORT)) {
-                    char *extra_mime_headers = NULL;
-                    if (mode == MODE_SEPARATE) mk_separate_file(&ff);
-                    ff.email_count++;
-                    DEBUG_MAIN(("main: Processing Email\n"));
-                    if ((ff.type != PST_TYPE_NOTE) && (ff.type != PST_TYPE_REPORT)) {
-                        DEBUG_MAIN(("main: I have an email type %"PRIi32", but the folder type %"PRIi32" isn't an email folder. Processing anyway\n", item->type, ff.type));
-                    }
-                    write_normal_email(ff.output, ff.name, item, mode, mode_MH, &pstfile, save_rtf_body, &extra_mime_headers);
+        } else if (item->contact && (item->type == PST_TYPE_CONTACT)) {
+            if (!ff.type) ff.type = item->type;
+            DEBUG_MAIN(("main: Processing Contact\n"));
+            if (ff.type != PST_TYPE_CONTACT) {
+                ff.skip_count++;
+                DEBUG_MAIN(("main: I have a contact, but the folder type %"PRIi32" isn't a contacts folder. Skipping it\n", ff.type));
+            }
+            else {
+                ff.item_count++;
+                if (mode == MODE_SEPARATE) mk_separate_file(&ff);
+                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->journal && (item->type == PST_TYPE_JOURNAL)) {
-                    if (mode == MODE_SEPARATE) mk_separate_file(&ff);
-                    ff.email_count++;
-                    DEBUG_MAIN(("main: Processing Journal Entry\n"));
-                    if (ff.type != PST_TYPE_JOURNAL) {
-                        DEBUG_MAIN(("main: I have a journal entry, but the folder type %"PRIi32" isn't a journal folder. Processing anyway\n", ff.type));
-                    }
-                    fprintf(ff.output, "BEGIN:VJOURNAL\n");
-                    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");
+        } else if (item->email && (item->type == PST_TYPE_NOTE || item->type == PST_TYPE_REPORT)) {
+            if (!ff.type) ff.type = item->type;
+            DEBUG_MAIN(("main: Processing Email\n"));
+            if ((ff.type != PST_TYPE_NOTE) && (ff.type != PST_TYPE_REPORT)) {
+                ff.skip_count++;
+                DEBUG_MAIN(("main: I have an email type %"PRIi32", but the folder type %"PRIi32" isn't an email folder. Skipping it\n", item->type, ff.type));
+            }
+            else {
+                char *extra_mime_headers = NULL;
+                ff.item_count++;
+                if (mode == MODE_SEPARATE) mk_separate_file(&ff);
+                write_normal_email(ff.output, ff.name, item, mode, mode_MH, &pstfile, save_rtf_body, &extra_mime_headers);
+            }
 
-                } else if (item->appointment && (item->type == PST_TYPE_APPOINTMENT)) {
-                    if (mode == MODE_SEPARATE) mk_separate_file(&ff);
-                    ff.email_count++;
-                    DEBUG_MAIN(("main: Processing Appointment Entry\n"));
-                    if (ff.type != PST_TYPE_APPOINTMENT) {
-                        DEBUG_MAIN(("main: I have an appointment, but folder type %"PRIi32" isn't an appointment folder. Processing anyway\n", ff.type));
-                    }
-                    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
-                    DEBUG_MAIN(("item with message store content, type %i %s folder type %i, skipping it\n", item->type, item->ascii_type, ff.type));
+        } else if (item->journal && (item->type == PST_TYPE_JOURNAL)) {
+            if (!ff.type) ff.type = item->type;
+            DEBUG_MAIN(("main: Processing Journal Entry\n"));
+            if (ff.type != PST_TYPE_JOURNAL) {
+                ff.skip_count++;
+                DEBUG_MAIN(("main: I have a journal entry, but the folder type %"PRIi32" isn't a journal folder. Skipping it\n", ff.type));
+            }
+            else {
+                ff.item_count++;
+                if (mode == MODE_SEPARATE) mk_separate_file(&ff);
+                fprintf(ff.output, "BEGIN:VJOURNAL\n");
+                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");
+            }
 
-                } else {
-                    // 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.str));
-                }
-                pst_freeItem(item);
-            } else {
+        } else if (item->appointment && (item->type == PST_TYPE_APPOINTMENT)) {
+            if (!ff.type) ff.type = item->type;
+            DEBUG_MAIN(("main: Processing Appointment Entry\n"));
+            if (ff.type != PST_TYPE_APPOINTMENT) {
                 ff.skip_count++;
-                DEBUG_MAIN(("main: A NULL item was seen\n"));
+                DEBUG_MAIN(("main: I have an appointment, but the folder type %"PRIi32" isn't an appointment folder. Skipping it\n", ff.type));
+            }
+            else {
+                ff.item_count++;
+                if (mode == MODE_SEPARATE) mk_separate_file(&ff);
+                write_appointment(ff.output, item, item->appointment, item->create_date, item->modify_date);
             }
-            d_ptr = d_ptr->next;
+
+        } else if (item->message_store) {
+            // there should only be one message_store, and we have already done it
+            ff.skip_count++;
+            DEBUG_MAIN(("item with message store content, type %i %s folder type %i, skipping it\n", item->type, item->ascii_type, ff.type));
+
+        } else {
+            ff.skip_count++;
+            DEBUG_MAIN(("main: Unknown item type %i (%s) name (%s)\n",
+                        item->type, item->ascii_type, item->file_as.str));
         }
+        pst_freeItem(item);
     }
     close_enter_dir(&ff);
     DEBUG_RET();
@@ -665,10 +686,10 @@
     const int name_offset = 1;
     DEBUG_ENT("mk_separate_file");
     DEBUG_MAIN(("opening next file to save email\n"));
-    if (f->email_count > 999999999) { // bigger than nine 9's
+    if (f->item_count > 999999999) { // bigger than nine 9's
         DIE(("mk_separate_file: The number of emails in this folder has become too high to handle"));
     }
-    sprintf(f->name, SEP_MAIL_FILE_TEMPLATE, f->email_count + name_offset);
+    sprintf(f->name, SEP_MAIL_FILE_TEMPLATE, f->item_count + name_offset);
     if (f->output) fclose(f->output);
     f->output = NULL;
     check_filename(f->name);
@@ -732,7 +753,7 @@
                                                     : attach->filename1.str;
     DEBUG_ENT("write_separate_attachment");
 
-    if (!attach->data) {
+    if (!attach->data.data) {
         // make sure we can fetch data from the id
         pst_index_ll *ptr = pst_getID(pst, attach->i_id);
         if (!ptr) {
@@ -765,8 +786,8 @@
     if (!(fp = fopen(temp, "w"))) {
         WARN(("write_separate_attachment: Cannot open attachment save file \"%s\"\n", temp));
     } else {
-        if (attach->data)
-            pst_fwrite(attach->data, (size_t)1, attach->size, fp);
+        if (attach->data.data)
+            pst_fwrite(attach->data.data, (size_t)1, attach->data.size, fp);
         else {
             (void)pst_attach_to_file(pst, attach, fp);
         }
@@ -810,9 +831,9 @@
     char *attach_filename;
     char *enc = NULL; // base64 encoded attachment
     DEBUG_ENT("write_inline_attachment");
-    DEBUG_EMAIL(("Attachment Size is %"PRIu64", id %#"PRIx64"\n", (uint64_t)attach->size, attach->i_id));
-    if (attach->data) {
-        enc = base64_encode (attach->data, attach->size);
+    DEBUG_EMAIL(("Attachment Size is %"PRIu64", id %#"PRIx64"\n", (uint64_t)attach->data.size, attach->i_id));
+    if (attach->data.data) {
+        enc = base64_encode (attach->data.data, attach->data.size);
         if (!enc) {
             DEBUG_EMAIL(("ERROR base64_encode returned NULL. Must have failed\n"));
             DEBUG_RET();
@@ -846,7 +867,7 @@
         fprintf(f_output, "Content-Disposition: attachment; filename=\"%s\"\n\n", attach_filename);
     }
 
-    if (attach->data) {
+    if (attach->data.data) {
         pst_fwrite(enc, 1, strlen(enc), f_output);
         DEBUG_EMAIL(("Attachment Size after encoding is %i\n", strlen(enc)));
         free(enc);  // caught by valgrind
@@ -1256,9 +1277,9 @@
         // multipart/report for DSN/MDN reports
         fprintf(f_output, "Content-Type: multipart/report; report-type=%s;\n\tboundary=\"%s\"\n", body_report, boundary);
     }
-    else if (item->attach || (item->email->rtf_compressed && save_rtf)
-                          || item->email->encrypted_body
-                          || item->email->encrypted_htmlbody) {
+    else if (item->attach || (item->email->rtf_compressed.data && save_rtf)
+                          || item->email->encrypted_body.data
+                          || item->email->encrypted_htmlbody.data) {
         // use multipart/mixed if we have attachments
         fprintf(f_output, "Content-Type: multipart/mixed;\n\tboundary=\"%s\"\n", boundary);
     } else {
@@ -1282,43 +1303,43 @@
         write_body_part(f_output, &item->email->htmlbody, "text/html", body_charset, boundary, pst);
     }
 
-    if (item->email->rtf_compressed && save_rtf) {
+    if (item->email->rtf_compressed.data && save_rtf) {
         pst_item_attach* attach = (pst_item_attach*)xmalloc(sizeof(pst_item_attach));
         DEBUG_EMAIL(("Adding RTF body as attachment\n"));
         memset(attach, 0, sizeof(pst_item_attach));
         attach->next = item->attach;
         item->attach = attach;
-        attach->data = lzfu_decompress(item->email->rtf_compressed, item->email->rtf_compressed_size, &attach->size);
+        attach->data.data         = lzfu_decompress(item->email->rtf_compressed.data, item->email->rtf_compressed.size, &attach->data.size);
         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) {
+    if (item->email->encrypted_body.data || item->email->encrypted_htmlbody.data) {
         // if either the body or htmlbody is encrypted, add them as attachments
-        if (item->email->encrypted_body) {
+        if (item->email->encrypted_body.data) {
             pst_item_attach* attach = (pst_item_attach*)xmalloc(sizeof(pst_item_attach));
             DEBUG_EMAIL(("Adding Encrypted Body as attachment\n"));
             attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach));
             memset(attach, 0, sizeof(pst_item_attach));
             attach->next = item->attach;
             item->attach = attach;
-            attach->data = item->email->encrypted_body;
-            attach->size = item->email->encrypted_body_size;
-            item->email->encrypted_body = NULL;
+            attach->data.data = item->email->encrypted_body.data;
+            attach->data.size = item->email->encrypted_body.size;
+            item->email->encrypted_body.data = NULL;
         }
 
-        if (item->email->encrypted_htmlbody) {
+        if (item->email->encrypted_htmlbody.data) {
             pst_item_attach* attach = (pst_item_attach*)xmalloc(sizeof(pst_item_attach));
             DEBUG_EMAIL(("Adding encrypted HTML body as attachment\n"));
             attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach));
             memset(attach, 0, sizeof(pst_item_attach));
             attach->next = item->attach;
             item->attach = attach;
-            attach->data = item->email->encrypted_htmlbody;
-            attach->size = item->email->encrypted_htmlbody_size;
-            item->email->encrypted_htmlbody = NULL;
+            attach->data.data = item->email->encrypted_htmlbody.data;
+            attach->data.size = item->email->encrypted_htmlbody.size;
+            item->email->encrypted_htmlbody.data = NULL;
         }
         write_email_body(f_output, "The body of this email is encrypted. This isn't supported yet, but the body is now an attachment\n");
     }
@@ -1332,12 +1353,12 @@
             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.str && !strcmp(attach->mimetype.str, RFC822)) {
+            if (!attach->data.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);
             }
-            else if (attach->data || attach->i_id) {
+            else if (attach->data.data || attach->i_id) {
                 if (mode == MODE_SEPARATE && !mode_MH)
                     write_separate_attachment(f_name, attach, ++attach_num, pst);
                 else
@@ -1585,10 +1606,10 @@
 void create_enter_dir(struct file_ll* f, pst_item *item)
 {
     pst_convert_utf8(item, &item->file_as);
-    f->email_count  = 0;
+    f->item_count  = 0;
     f->skip_count   = 0;
     f->type         = item->type;
-    f->stored_count = (item->folder) ? item->folder->email_count : 0;
+    f->stored_count = (item->folder) ? item->folder->item_count : 0;
 
     DEBUG_ENT("create_enter_dir");
     if (mode == MODE_KMAIL)
@@ -1600,7 +1621,6 @@
         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.str)+strlen(OUTPUT_TEMPLATE)+1);
         sprintf(f->name, OUTPUT_TEMPLATE, item->file_as.str);
@@ -1647,10 +1667,10 @@
 
 void close_enter_dir(struct file_ll *f)
 {
-    DEBUG_MAIN(("main: Email Count for folder %s is %i\n", f->dname, f->email_count));
+    DEBUG_MAIN(("main: processed item count for folder %s is %i, skipped %i, total %i \n",
+                f->dname, f->item_count, f->skip_count, f->stored_count));
     if (output_mode != OUTPUT_QUIET)
-        printf("\t\"%s\" - %i items done, skipped %i, should have been %i\n",
-               f->dname, f->email_count, f->skip_count, f->stored_count);
+        printf("\t\"%s\" - %i items done.\n", f->dname, f->item_count);
     if (f->output) fclose(f->output);
     free(f->name);
     free(f->dname);