diff src/libpst.c @ 143:fdc58ad2c758 stable-0-6-28

fix embedded rfc822 messages with attachments
author Carl Byington <carl@five-ten-sg.com>
date Tue, 24 Feb 2009 12:33:49 -0800
parents 2189a6b8134e
children b47d04257b43
line wrap: on
line diff
--- a/src/libpst.c	Mon Feb 23 20:40:51 2009 -0800
+++ b/src/libpst.c	Tue Feb 24 12:33:49 2009 -0800
@@ -349,6 +349,26 @@
 }
 
 
+/**
+ * make a deep copy of part of the id2 mapping tree, for use
+ * by an attachment containing an embedded rfc822 message.
+ *
+ * @param   head  pointer to the subtree to be copied
+ * @return        pointer to the new copy of the subtree
+ */
+static pst_index2_ll* deep_copy(pst_index2_ll *head);
+static pst_index2_ll* deep_copy(pst_index2_ll *head)
+{
+    if (!head) return NULL;
+    pst_index2_ll* me = (pst_index2_ll*) xmalloc(sizeof(pst_index2_ll));
+    me->id2 = head->id2;
+    me->id  = head->id;
+    me->child = deep_copy(head->child);
+    me->next  = deep_copy(head->next);
+    return me;
+}
+
+
 pst_desc_ll* pst_getTopOfFolders(pst_file *pf, pst_item *root) {
     pst_desc_ll *topnode;
     uint32_t topid;
@@ -530,7 +550,7 @@
     na = pst_parse_block(pf, p->desc->id, id2_head, NULL);
     if (!na) {
         DEBUG_WARN(("Cannot process desc block for item 0x61. Not loading extended Attributes\n"));
-        if (id2_head) pst_free_id2(id2_head);
+        pst_free_id2(id2_head);
         DEBUG_RET();
         return 0;
     }
@@ -548,7 +568,7 @@
     }
 
     if (!buffer) {
-        if (na) pst_free_list(na);
+        pst_free_list(na);
         DEBUG_WARN(("No extended attributes buffer found. Not processing\n"));
         DEBUG_RET();
         return 0;
@@ -620,8 +640,8 @@
         LE16_CPU(xattrib.map);
         bptr += sizeof(xattrib);
     }
-    if (id2_head) pst_free_id2(id2_head);
-    if (na)       pst_free_list(na);
+    pst_free_id2(id2_head);
+    pst_free_list(na);
     pf->x_head = p_head;
     DEBUG_RET();
     return 1;
@@ -1028,10 +1048,10 @@
 }
 
 
-pst_item* pst_parse_item(pst_file *pf, pst_desc_ll *d_ptr) {
+pst_item* pst_parse_item(pst_file *pf, pst_desc_ll *d_ptr, pst_index2_ll *m_head) {
     pst_num_array * list;
-    pst_index2_ll *id2_head = NULL;
-    pst_index_ll *id_ptr = NULL;
+    pst_index2_ll *id2_head = m_head;
+    pst_index2_ll *id2_ptr  = NULL;
     pst_item *item = NULL;
     pst_item_attach *attach = NULL;
     int32_t x;
@@ -1049,14 +1069,18 @@
     }
 
     if (d_ptr->list_index) {
+        if (m_head) {
+            DEBUG_WARN(("supplied master head, but have a list that is building a new id2_head"));
+            m_head = NULL;
+        }
         id2_head = pst_build_id2(pf, d_ptr->list_index);
-        (void)pst_printID2ptr(id2_head);
     }
+    pst_printID2ptr(id2_head);
 
     list = pst_parse_block(pf, d_ptr->desc->id, id2_head, NULL);
     if (!list) {
         DEBUG_WARN(("pst_parse_block() returned an error for d_ptr->desc->id [%#"PRIx64"]\n", d_ptr->desc->id));
-        if (id2_head) pst_free_id2(id2_head);
+        if (!m_head) pst_free_id2(id2_head);
         DEBUG_RET();
         return NULL;
     }
@@ -1066,48 +1090,42 @@
 
     if (pst_process(list, item, NULL)) {
         DEBUG_WARN(("pst_process() returned non-zero value. That is an error\n"));
-        if (item)     pst_freeItem(item);
-        if (list)     pst_free_list(list);
-        if (id2_head) pst_free_id2(id2_head);
+        pst_freeItem(item);
+        pst_free_list(list);
+        if (!m_head) pst_free_id2(id2_head);
         DEBUG_RET();
         return NULL;
     }
-    if (list) pst_free_list(list);
-    list = NULL;
-
-    if ((id_ptr = pst_getID2(id2_head, (uint64_t)0x692))) {
+    pst_free_list(list);
+
+    if ((id2_ptr = pst_getID2(id2_head, (uint64_t)0x692))) {
         // DSN/MDN reports?
         DEBUG_EMAIL(("DSN/MDN processing \n"));
-        if ((list = pst_parse_block(pf, id_ptr->id, id2_head, NULL)) == NULL) {
+        list = pst_parse_block(pf, id2_ptr->id->id, id2_head, NULL);
+        if (!list) {
             DEBUG_WARN(("ERROR error processing main DSN/MDN record\n"));
-            if (item)     pst_freeItem(item);
-            if (list)     pst_free_list(list);
-            if (id2_head) pst_free_id2(id2_head);
+            if (!m_head) pst_free_id2(id2_head);
             DEBUG_RET();
             return item;
         }
-        else {
-            for (x=0; x < list->count_array; x++) {
-                attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach));
-                memset(attach, 0, sizeof(pst_item_attach));
-                attach->next = item->attach;
-                item->attach = attach;
-            }
-
-            if (pst_process(list, item, item->attach)) {
-                DEBUG_WARN(("ERROR pst_process() failed with attachments\n"));
-                if (item)     pst_freeItem(item);
-                if (list)     pst_free_list(list);
-                if (id2_head) pst_free_id2(id2_head);
-                DEBUG_RET();
-                return NULL;
-            }
-            if (list) pst_free_list(list);
-            list = NULL;
+        for (x=0; x < list->count_array; x++) {
+            attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach));
+            memset(attach, 0, sizeof(pst_item_attach));
+            attach->next = item->attach;
+            item->attach = attach;
         }
+        if (pst_process(list, item, item->attach)) {
+            DEBUG_WARN(("ERROR pst_process() failed with DSN/MDN attachments\n"));
+            pst_freeItem(item);
+            pst_free_list(list);
+            if (!m_head) pst_free_id2(id2_head);
+            DEBUG_RET();
+            return NULL;
+        }
+        pst_free_list(list);
     }
 
-    if ((id_ptr = pst_getID2(id2_head, (uint64_t)0x671))) {
+    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"));
@@ -1117,78 +1135,75 @@
         //}
 
         DEBUG_EMAIL(("ATTACHMENT processing attachment\n"));
-        if ((list = pst_parse_block(pf, id_ptr->id, id2_head, NULL)) == NULL) {
+        list = pst_parse_block(pf, id2_ptr->id->id, id2_head, NULL);
+        if (!list) {
             DEBUG_WARN(("ERROR error processing main attachment record\n"));
-            if (id2_head) pst_free_id2(id2_head);
+            if (!m_head) pst_free_id2(id2_head);
             DEBUG_RET();
             return item;
         }
-        else {
-            for (x=0; x < list->count_array; x++) {
-                attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach));
-                memset(attach, 0, sizeof(pst_item_attach));
-                attach->next = item->attach;
-                item->attach = attach;
-            }
-
-            if (pst_process(list, item, item->attach)) {
-                DEBUG_WARN(("ERROR pst_process() failed with attachments\n"));
-                if (item)     pst_freeItem(item);
-                if (list)     pst_free_list(list);
-                if (id2_head) pst_free_id2(id2_head);
-                DEBUG_RET();
-                return NULL;
+        for (x=0; x < list->count_array; x++) {
+            attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach));
+            memset(attach, 0, sizeof(pst_item_attach));
+            attach->next = item->attach;
+            item->attach = attach;
+        }
+        if (pst_process(list, item, item->attach)) {
+            DEBUG_WARN(("ERROR pst_process() failed with attachments\n"));
+            pst_freeItem(item);
+            pst_free_list(list);
+            if (!m_head) pst_free_id2(id2_head);
+            DEBUG_RET();
+            return NULL;
+        }
+        pst_free_list(list);
+
+        // now we will have initial information of each attachment stored in item->attach...
+        // we must now read the secondary record for each based on the id2 val associated with
+        // each attachment
+        attach = item->attach;
+        while (attach) {
+            DEBUG_WARN(("initial attachment id2 %#"PRIx64"\n", attach->id2_val));
+            if ((id2_ptr = pst_getID2(id2_head, attach->id2_val))) {
+                DEBUG_WARN(("initial attachment id2 found id %#"PRIx64"\n", id2_ptr->id->id));
+                // id_ptr is a record describing the attachment
+                // we pass NULL instead of id2_head cause we don't want it to
+                // load all the extra stuff here.
+                list = pst_parse_block(pf, id2_ptr->id->id, NULL, NULL);
+                if (!list) {
+                    DEBUG_WARN(("ERROR error processing an attachment record\n"));
+                    attach = attach->next;
+                    continue;
+                }
+                if (list->count_array > 1) {
+                    DEBUG_WARN(("ERROR probably fatal, list count array will overrun attach structure.\n"));
+                }
+                if (pst_process(list, item, attach)) {
+                    DEBUG_WARN(("ERROR pst_process() failed with an attachment\n"));
+                    pst_free_list(list);
+                    attach = attach->next;
+                    continue;
+                }
+                pst_free_list(list);
+                id2_ptr = pst_getID2(id2_head, attach->id2_val);
+                if (id2_ptr) {
+                    DEBUG_WARN(("second pass attachment updating id2 found id %#"PRIx64"\n", id2_ptr->id->id));
+                    // id2_val has been updated to the ID2 value of the datablock containing the
+                    // attachment data
+                    attach->id_val   = id2_ptr->id->id;
+                    attach->id2_head = deep_copy(id2_ptr->child);
+                } else {
+                    DEBUG_WARN(("have not located the correct value for the attachment [%#"PRIx64"]\n", attach->id2_val));
+                }
+            } else {
+                DEBUG_WARN(("ERROR cannot locate id2 value %#"PRIx64"\n", attach->id2_val));
+                attach->id2_val = 0;    // suppress this missing attachment
             }
-            if (list) pst_free_list(list);
-            list = NULL;
-
-            // now we will have initial information of each attachment stored in item->attach...
-            // we must now read the secondary record for each based on the id2 val associated with
-            // each attachment
-            attach = item->attach;
-            while (attach) {
-                DEBUG_WARN(("initial attachment id2 %#"PRIx64"\n", attach->id2_val));
-                if ((id_ptr = pst_getID2(id2_head, attach->id2_val))) {
-                    DEBUG_WARN(("initial attachment id2 found id %#"PRIx64"\n", id_ptr->id));
-                    // id_ptr is a record describing the attachment
-                    // we pass NULL instead of id2_head cause we don't want it to
-                    // load all the extra stuff here.
-                    if ((list = pst_parse_block(pf, id_ptr->id, NULL, NULL)) == NULL) {
-                        DEBUG_WARN(("ERROR error processing an attachment record\n"));
-                        attach = attach->next;
-                        continue;
-                    }
-                    if (list->count_array > 1) {
-                        DEBUG_WARN(("ERROR probably fatal, list count array will overrun attach structure.\n"));
-                    }
-                    if (pst_process(list, item, attach)) {
-                        DEBUG_WARN(("ERROR pst_process() failed with an attachment\n"));
-                        if (list) pst_free_list(list);
-                        list = NULL;
-                        attach = attach->next;
-                        continue;
-                    }
-                    if (list) pst_free_list(list);
-                    list = NULL;
-                    id_ptr = pst_getID2(id2_head, attach->id2_val);
-                    if (id_ptr) {
-                        DEBUG_WARN(("second pass attachment updating id2 found id %#"PRIx64"\n", id_ptr->id));
-                        // id2_val has been updated to the ID2 value of the datablock containing the
-                        // attachment data
-                        attach->id_val = id_ptr->id;
-                    } else {
-                        DEBUG_WARN(("have not located the correct value for the attachment [%#"PRIx64"]\n", attach->id2_val));
-                    }
-                } else {
-                    DEBUG_WARN(("ERROR cannot locate id2 value %#"PRIx64"\n", attach->id2_val));
-                    attach->id2_val = 0;    // suppress this missing attachment
-                }
-                attach = attach->next;
-            }
+            attach = attach->next;
         }
     }
 
-    if (id2_head) pst_free_id2(id2_head);
+    if (!m_head) pst_free_id2(id2_head);
     DEBUG_RET();
     return item;
 }
@@ -1508,7 +1523,7 @@
             } else {
                 WARN(("Missing code for block_type %i\n", block_type));
                 freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
-                if (na_head) pst_free_list(na_head);
+                pst_free_list(na_head);
                 DEBUG_RET();
                 return NULL;
             }
@@ -1666,7 +1681,7 @@
             } else {
                 WARN(("ERROR Unknown ref_type %#hx\n", table_rec.ref_type));
                 freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
-                if (na_head) pst_free_list(na_head);
+                pst_free_list(na_head);
                 DEBUG_RET();
                 return NULL;
             }
@@ -3639,9 +3654,9 @@
             }
             free(list->items);
         }
-        l = list;
-        list = list->next;
-        free (l);
+        l = list->next;
+        free (list);
+        list = l;
     }
     DEBUG_RET();
 }
@@ -3779,8 +3794,22 @@
 }
 
 
+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(attach->data);
+        pst_free_id2(attach->id2_head);
+        t = attach->next;
+        free(attach);
+        attach = t;
+    }
+}
+
+
 void pst_freeItem(pst_item *item) {
-    pst_item_attach *t;
     pst_item_extra_field *et;
 
     DEBUG_ENT("pst_freeItem");
@@ -3944,15 +3973,9 @@
             SAFE_FREE(item->contact->work_address_postofficebox);
             free(item->contact);
         }
-        while (item->attach) {
-            SAFE_FREE(item->attach->filename1);
-            SAFE_FREE(item->attach->filename2);
-            SAFE_FREE(item->attach->mimetype);
-            SAFE_FREE(item->attach->data);
-            t = item->attach->next;
-            free(item->attach);
-            item->attach = t;
-        }
+
+        pst_free_attach(item->attach);
+
         while (item->extra_fields) {
             SAFE_FREE(item->extra_fields->field_name);
             SAFE_FREE(item->extra_fields->value);
@@ -4092,14 +4115,14 @@
 }
 
 
-pst_index_ll *pst_getID2(pst_index2_ll *head, uint64_t id) {
+pst_index2_ll *pst_getID2(pst_index2_ll *head, uint64_t id2) {
     DEBUG_ENT("pst_getID2");
-    DEBUG_INDEX(("looking for id = %#"PRIx64"\n", id));
+    DEBUG_INDEX(("looking for id2 = %#"PRIx64"\n", id2));
     pst_index2_ll *ptr = head;
     while (ptr) {
-        if (ptr->id2 == id) break;
+        if (ptr->id2 == id2) break;
         if (ptr->child) {
-            pst_index_ll *rc = pst_getID2(ptr->child, id);
+            pst_index2_ll *rc = pst_getID2(ptr->child, id2);
             if (rc) {
                 DEBUG_RET();
                 return rc;
@@ -4107,13 +4130,12 @@
         }
         ptr = ptr->next;
     }
-    if (ptr) {
-        if (ptr->id) {DEBUG_INDEX(("Found value %#"PRIx64"\n", ptr->id->id));   }
-        else         {DEBUG_INDEX(("Found value, though it is NULL!\n"));}
+    if (ptr && ptr->id) {
+        DEBUG_INDEX(("Found value %#"PRIx64"\n", ptr->id->id));
         DEBUG_RET();
-        return ptr->id;
+        return ptr;
     }
-    //DEBUG_INDEX(("ERROR Not Found\n"));
+    DEBUG_INDEX(("ERROR Not Found\n"));
     DEBUG_RET();
     return NULL;
 }
@@ -4396,7 +4418,7 @@
 #define PST_PTR_BLOCK_SIZE 0x120
 size_t pst_ff_getID2block(pst_file *pf, uint64_t id2, pst_index2_ll *id2_head, char** buf) {
     size_t ret;
-    pst_index_ll* ptr;
+    pst_index2_ll* ptr;
     pst_holder h = {buf, NULL, 0};
     DEBUG_ENT("pst_ff_getID2block");
     ptr = pst_getID2(id2_head, id2);
@@ -4406,7 +4428,7 @@
         DEBUG_RET();
         return 0;
     }
-    ret = pst_ff_getID2data(pf, ptr, &h);
+    ret = pst_ff_getID2data(pf, ptr->id, &h);
     DEBUG_RET();
     return ret;
 }