Main Page | Namespace List | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

libpst.c

Go to the documentation of this file.
00001 /***
00002  * libpst.c
00003  * Part of the LibPST project
00004  * Written by David Smith
00005  *            dave.s@earthcorp.com
00006  */
00007 
00008 #include "define.h"
00009 
00010 
00011 // switch to maximal packing for our own internal structures
00012 // use the same code as in libpst.h
00013 #ifdef _MSC_VER
00014     #pragma pack(push, 1)
00015 #endif
00016 #if defined(__GNUC__) || defined (__SUNPRO_C) || defined(__SUNPRO_CC)
00017     #pragma pack(1)
00018 #endif
00019 
00020 
00021 #define ASSERT(x) { if(!(x)) raise( SIGSEGV ); }
00022 
00023 #define INDEX_TYPE32            0x0E
00024 #define INDEX_TYPE32A           0x0F    // unknown, but assumed to be similar for now
00025 #define INDEX_TYPE64            0x17
00026 #define INDEX_TYPE64A           0x15    // http://sourceforge.net/projects/libpff/
00027 #define INDEX_TYPE_OFFSET       (int64_t)0x0A
00028 
00029 #define FILE_SIZE_POINTER32     (int64_t)0xA8
00030 #define INDEX_POINTER32         (int64_t)0xC4
00031 #define INDEX_BACK32            (int64_t)0xC0
00032 #define SECOND_POINTER32        (int64_t)0xBC
00033 #define SECOND_BACK32           (int64_t)0xB8
00034 #define ENC_TYPE32              (int64_t)0x1CD
00035 
00036 #define FILE_SIZE_POINTER64     (int64_t)0xB8
00037 #define INDEX_POINTER64         (int64_t)0xF0
00038 #define INDEX_BACK64            (int64_t)0xE8
00039 #define SECOND_POINTER64        (int64_t)0xE0
00040 #define SECOND_BACK64           (int64_t)0xD8
00041 #define ENC_TYPE64              (int64_t)0x201
00042 
00043 #define FILE_SIZE_POINTER ((pf->do_read64) ? FILE_SIZE_POINTER64 : FILE_SIZE_POINTER32)
00044 #define INDEX_POINTER     ((pf->do_read64) ? INDEX_POINTER64     : INDEX_POINTER32)
00045 #define INDEX_BACK        ((pf->do_read64) ? INDEX_BACK64        : INDEX_BACK32)
00046 #define SECOND_POINTER    ((pf->do_read64) ? SECOND_POINTER64    : SECOND_POINTER32)
00047 #define SECOND_BACK       ((pf->do_read64) ? SECOND_BACK64       : SECOND_BACK32)
00048 #define ENC_TYPE          ((pf->do_read64) ? ENC_TYPE64          : ENC_TYPE32)
00049 
00050 #define PST_SIGNATURE 0x4E444221
00051 
00052 
00053 struct pst_table_ptr_struct32{
00054   uint32_t start;
00055   uint32_t u1;
00056   uint32_t offset;
00057 };
00058 
00059 
00060 struct pst_table_ptr_structn{
00061   uint64_t start;
00062   uint64_t u1;
00063   uint64_t offset;
00064 };
00065 
00066 
00067 typedef struct pst_block_header {
00068     uint16_t type;
00069     uint16_t count;
00070 } pst_block_header;
00071 
00072 
00073 typedef struct pst_id2_assoc32 {
00074     uint32_t id2;
00075     uint32_t id;
00076     uint32_t child_id;
00077 } pst_id2_assoc32;
00078 
00079 
00080 typedef struct pst_id2_assoc {
00081     uint32_t id2;       // only 32 bit here
00082     uint16_t unknown1;
00083     uint16_t unknown2;
00084     uint64_t id;
00085     uint64_t child_id;
00086 } pst_id2_assoc;
00087 
00088 
00089 typedef struct pst_table3_rec32 {
00090     uint32_t id;
00091 } pst_table3_rec32; //for type 3 (0x0101) blocks
00092 
00093 
00094 typedef struct pst_table3_rec {
00095     uint64_t id;
00096 } pst_table3_rec;   //for type 3 (0x0101) blocks
00097 
00098 
00099 typedef struct pst_block_hdr {
00100     uint16_t index_offset;
00101     uint16_t type;
00102     uint32_t offset;
00103 } pst_block_hdr;
00104 
00105 
00110 static unsigned char comp_enc [] = {
00111     0x47, 0xf1, 0xb4, 0xe6, 0x0b, 0x6a, 0x72, 0x48, 0x85, 0x4e, 0x9e, 0xeb, 0xe2, 0xf8, 0x94, 0x53,
00112     0xe0, 0xbb, 0xa0, 0x02, 0xe8, 0x5a, 0x09, 0xab, 0xdb, 0xe3, 0xba, 0xc6, 0x7c, 0xc3, 0x10, 0xdd,
00113     0x39, 0x05, 0x96, 0x30, 0xf5, 0x37, 0x60, 0x82, 0x8c, 0xc9, 0x13, 0x4a, 0x6b, 0x1d, 0xf3, 0xfb,
00114     0x8f, 0x26, 0x97, 0xca, 0x91, 0x17, 0x01, 0xc4, 0x32, 0x2d, 0x6e, 0x31, 0x95, 0xff, 0xd9, 0x23,
00115     0xd1, 0x00, 0x5e, 0x79, 0xdc, 0x44, 0x3b, 0x1a, 0x28, 0xc5, 0x61, 0x57, 0x20, 0x90, 0x3d, 0x83,
00116     0xb9, 0x43, 0xbe, 0x67, 0xd2, 0x46, 0x42, 0x76, 0xc0, 0x6d, 0x5b, 0x7e, 0xb2, 0x0f, 0x16, 0x29,
00117     0x3c, 0xa9, 0x03, 0x54, 0x0d, 0xda, 0x5d, 0xdf, 0xf6, 0xb7, 0xc7, 0x62, 0xcd, 0x8d, 0x06, 0xd3,
00118     0x69, 0x5c, 0x86, 0xd6, 0x14, 0xf7, 0xa5, 0x66, 0x75, 0xac, 0xb1, 0xe9, 0x45, 0x21, 0x70, 0x0c,
00119     0x87, 0x9f, 0x74, 0xa4, 0x22, 0x4c, 0x6f, 0xbf, 0x1f, 0x56, 0xaa, 0x2e, 0xb3, 0x78, 0x33, 0x50,
00120     0xb0, 0xa3, 0x92, 0xbc, 0xcf, 0x19, 0x1c, 0xa7, 0x63, 0xcb, 0x1e, 0x4d, 0x3e, 0x4b, 0x1b, 0x9b,
00121     0x4f, 0xe7, 0xf0, 0xee, 0xad, 0x3a, 0xb5, 0x59, 0x04, 0xea, 0x40, 0x55, 0x25, 0x51, 0xe5, 0x7a,
00122     0x89, 0x38, 0x68, 0x52, 0x7b, 0xfc, 0x27, 0xae, 0xd7, 0xbd, 0xfa, 0x07, 0xf4, 0xcc, 0x8e, 0x5f,
00123     0xef, 0x35, 0x9c, 0x84, 0x2b, 0x15, 0xd5, 0x77, 0x34, 0x49, 0xb6, 0x12, 0x0a, 0x7f, 0x71, 0x88,
00124     0xfd, 0x9d, 0x18, 0x41, 0x7d, 0x93, 0xd8, 0x58, 0x2c, 0xce, 0xfe, 0x24, 0xaf, 0xde, 0xb8, 0x36,
00125     0xc8, 0xa1, 0x80, 0xa6, 0x99, 0x98, 0xa8, 0x2f, 0x0e, 0x81, 0x65, 0x73, 0xe4, 0xc2, 0xa2, 0x8a,
00126     0xd4, 0xe1, 0x11, 0xd0, 0x08, 0x8b, 0x2a, 0xf2, 0xed, 0x9a, 0x64, 0x3f, 0xc1, 0x6c, 0xf9, 0xec
00127 };
00128 
00131 static unsigned char comp_high1 [] = {
00132     0x41, 0x36, 0x13, 0x62, 0xa8, 0x21, 0x6e, 0xbb, 0xf4, 0x16, 0xcc, 0x04, 0x7f, 0x64, 0xe8, 0x5d,
00133     0x1e, 0xf2, 0xcb, 0x2a, 0x74, 0xc5, 0x5e, 0x35, 0xd2, 0x95, 0x47, 0x9e, 0x96, 0x2d, 0x9a, 0x88,
00134     0x4c, 0x7d, 0x84, 0x3f, 0xdb, 0xac, 0x31, 0xb6, 0x48, 0x5f, 0xf6, 0xc4, 0xd8, 0x39, 0x8b, 0xe7,
00135     0x23, 0x3b, 0x38, 0x8e, 0xc8, 0xc1, 0xdf, 0x25, 0xb1, 0x20, 0xa5, 0x46, 0x60, 0x4e, 0x9c, 0xfb,
00136     0xaa, 0xd3, 0x56, 0x51, 0x45, 0x7c, 0x55, 0x00, 0x07, 0xc9, 0x2b, 0x9d, 0x85, 0x9b, 0x09, 0xa0,
00137     0x8f, 0xad, 0xb3, 0x0f, 0x63, 0xab, 0x89, 0x4b, 0xd7, 0xa7, 0x15, 0x5a, 0x71, 0x66, 0x42, 0xbf,
00138     0x26, 0x4a, 0x6b, 0x98, 0xfa, 0xea, 0x77, 0x53, 0xb2, 0x70, 0x05, 0x2c, 0xfd, 0x59, 0x3a, 0x86,
00139     0x7e, 0xce, 0x06, 0xeb, 0x82, 0x78, 0x57, 0xc7, 0x8d, 0x43, 0xaf, 0xb4, 0x1c, 0xd4, 0x5b, 0xcd,
00140     0xe2, 0xe9, 0x27, 0x4f, 0xc3, 0x08, 0x72, 0x80, 0xcf, 0xb0, 0xef, 0xf5, 0x28, 0x6d, 0xbe, 0x30,
00141     0x4d, 0x34, 0x92, 0xd5, 0x0e, 0x3c, 0x22, 0x32, 0xe5, 0xe4, 0xf9, 0x9f, 0xc2, 0xd1, 0x0a, 0x81,
00142     0x12, 0xe1, 0xee, 0x91, 0x83, 0x76, 0xe3, 0x97, 0xe6, 0x61, 0x8a, 0x17, 0x79, 0xa4, 0xb7, 0xdc,
00143     0x90, 0x7a, 0x5c, 0x8c, 0x02, 0xa6, 0xca, 0x69, 0xde, 0x50, 0x1a, 0x11, 0x93, 0xb9, 0x52, 0x87,
00144     0x58, 0xfc, 0xed, 0x1d, 0x37, 0x49, 0x1b, 0x6a, 0xe0, 0x29, 0x33, 0x99, 0xbd, 0x6c, 0xd9, 0x94,
00145     0xf3, 0x40, 0x54, 0x6f, 0xf0, 0xc6, 0x73, 0xb8, 0xd6, 0x3e, 0x65, 0x18, 0x44, 0x1f, 0xdd, 0x67,
00146     0x10, 0xf1, 0x0c, 0x19, 0xec, 0xae, 0x03, 0xa1, 0x14, 0x7b, 0xa9, 0x0b, 0xff, 0xf8, 0xa3, 0xc0,
00147     0xa2, 0x01, 0xf7, 0x2e, 0xbc, 0x24, 0x68, 0x75, 0x0d, 0xfe, 0xba, 0x2f, 0xb5, 0xd0, 0xda, 0x3d
00148 };
00149 
00152 static unsigned char comp_high2 [] = {
00153     0x14, 0x53, 0x0f, 0x56, 0xb3, 0xc8, 0x7a, 0x9c, 0xeb, 0x65, 0x48, 0x17, 0x16, 0x15, 0x9f, 0x02,
00154     0xcc, 0x54, 0x7c, 0x83, 0x00, 0x0d, 0x0c, 0x0b, 0xa2, 0x62, 0xa8, 0x76, 0xdb, 0xd9, 0xed, 0xc7,
00155     0xc5, 0xa4, 0xdc, 0xac, 0x85, 0x74, 0xd6, 0xd0, 0xa7, 0x9b, 0xae, 0x9a, 0x96, 0x71, 0x66, 0xc3,
00156     0x63, 0x99, 0xb8, 0xdd, 0x73, 0x92, 0x8e, 0x84, 0x7d, 0xa5, 0x5e, 0xd1, 0x5d, 0x93, 0xb1, 0x57,
00157     0x51, 0x50, 0x80, 0x89, 0x52, 0x94, 0x4f, 0x4e, 0x0a, 0x6b, 0xbc, 0x8d, 0x7f, 0x6e, 0x47, 0x46,
00158     0x41, 0x40, 0x44, 0x01, 0x11, 0xcb, 0x03, 0x3f, 0xf7, 0xf4, 0xe1, 0xa9, 0x8f, 0x3c, 0x3a, 0xf9,
00159     0xfb, 0xf0, 0x19, 0x30, 0x82, 0x09, 0x2e, 0xc9, 0x9d, 0xa0, 0x86, 0x49, 0xee, 0x6f, 0x4d, 0x6d,
00160     0xc4, 0x2d, 0x81, 0x34, 0x25, 0x87, 0x1b, 0x88, 0xaa, 0xfc, 0x06, 0xa1, 0x12, 0x38, 0xfd, 0x4c,
00161     0x42, 0x72, 0x64, 0x13, 0x37, 0x24, 0x6a, 0x75, 0x77, 0x43, 0xff, 0xe6, 0xb4, 0x4b, 0x36, 0x5c,
00162     0xe4, 0xd8, 0x35, 0x3d, 0x45, 0xb9, 0x2c, 0xec, 0xb7, 0x31, 0x2b, 0x29, 0x07, 0x68, 0xa3, 0x0e,
00163     0x69, 0x7b, 0x18, 0x9e, 0x21, 0x39, 0xbe, 0x28, 0x1a, 0x5b, 0x78, 0xf5, 0x23, 0xca, 0x2a, 0xb0,
00164     0xaf, 0x3e, 0xfe, 0x04, 0x8c, 0xe7, 0xe5, 0x98, 0x32, 0x95, 0xd3, 0xf6, 0x4a, 0xe8, 0xa6, 0xea,
00165     0xe9, 0xf3, 0xd5, 0x2f, 0x70, 0x20, 0xf2, 0x1f, 0x05, 0x67, 0xad, 0x55, 0x10, 0xce, 0xcd, 0xe3,
00166     0x27, 0x3b, 0xda, 0xba, 0xd7, 0xc2, 0x26, 0xd4, 0x91, 0x1d, 0xd2, 0x1c, 0x22, 0x33, 0xf8, 0xfa,
00167     0xf1, 0x5a, 0xef, 0xcf, 0x90, 0xb6, 0x8b, 0xb5, 0xbd, 0xc0, 0xbf, 0x08, 0x97, 0x1e, 0x6c, 0xe2,
00168     0x61, 0xe0, 0xc6, 0xc1, 0x59, 0xab, 0xbb, 0x58, 0xde, 0x5f, 0xdf, 0x60, 0x79, 0x7e, 0xb2, 0x8a
00169 };
00170 
00171 
00172 int pst_open(pst_file *pf, char *name) {
00173     int32_t sig;
00174 
00175     unicode_init();
00176 
00177     DEBUG_ENT("pst_open");
00178 
00179     if (!pf) {
00180         WARN (("cannot be passed a NULL pst_file\n"));
00181         DEBUG_RET();
00182         return -1;
00183     }
00184     memset(pf, 0, sizeof(*pf));
00185 
00186     if ((pf->fp = fopen(name, "rb")) == NULL) {
00187         perror("Error opening PST file");
00188         DEBUG_RET();
00189         return -1;
00190     }
00191 
00192     // Check pst file magic
00193     if (pst_getAtPos(pf, 0, &sig, sizeof(sig)) != sizeof(sig)) {
00194         (void)fclose(pf->fp);
00195         WARN(("cannot read signature from PST file. Closing on error\n"));
00196         DEBUG_RET();
00197         return -1;
00198     }
00199     LE32_CPU(sig);
00200     DEBUG_INFO(("sig = %X\n", sig));
00201     if (sig != (int32_t)PST_SIGNATURE) {
00202         (void)fclose(pf->fp);
00203         WARN(("not a PST file that I know. Closing with error\n"));
00204         DEBUG_RET();
00205         return -1;
00206     }
00207 
00208     // read index type
00209     (void)pst_getAtPos(pf, INDEX_TYPE_OFFSET, &(pf->ind_type), sizeof(pf->ind_type));
00210     DEBUG_INFO(("index_type = %i\n", pf->ind_type));
00211     switch (pf->ind_type) {
00212         case INDEX_TYPE32 :
00213         case INDEX_TYPE32A :
00214             pf->do_read64 = 0;
00215             break;
00216         case INDEX_TYPE64 :
00217         case INDEX_TYPE64A :
00218             pf->do_read64 = 1;
00219             break;
00220         default:
00221             (void)fclose(pf->fp);
00222             WARN(("unknown .pst format, possibly newer than Outlook 2003 PST file?\n"));
00223             DEBUG_RET();
00224             return -1;
00225     }
00226 
00227     // read encryption setting
00228     (void)pst_getAtPos(pf, ENC_TYPE, &(pf->encryption), sizeof(pf->encryption));
00229     DEBUG_INFO(("encrypt = %i\n", pf->encryption));
00230 
00231     pf->index2_back  = pst_getIntAtPos(pf, SECOND_BACK);
00232     pf->index2       = pst_getIntAtPos(pf, SECOND_POINTER);
00233     pf->size         = pst_getIntAtPos(pf, FILE_SIZE_POINTER);
00234     DEBUG_INFO(("Pointer2 is %#"PRIx64", back pointer2 is %#"PRIx64"\n", pf->index2, pf->index2_back));
00235 
00236     pf->index1_back  = pst_getIntAtPos(pf, INDEX_BACK);
00237     pf->index1       = pst_getIntAtPos(pf, INDEX_POINTER);
00238     DEBUG_INFO(("Pointer1 is %#"PRIx64", back pointer2 is %#"PRIx64"\n", pf->index1, pf->index1_back));
00239 
00240     DEBUG_RET();
00241     return 0;
00242 }
00243 
00244 
00245 int pst_close(pst_file *pf) {
00246     DEBUG_ENT("pst_close");
00247     if (!pf->fp) {
00248         WARN(("cannot close NULL fp\n"));
00249         DEBUG_RET();
00250         return -1;
00251     }
00252     if (fclose(pf->fp)) {
00253         WARN(("fclose returned non-zero value\n"));
00254         DEBUG_RET();
00255         return -1;
00256     }
00257     // we must free the id linklist and the desc tree
00258     pst_free_id (pf->i_head);
00259     pst_free_desc (pf->d_head);
00260     pst_free_xattrib (pf->x_head);
00261     DEBUG_RET();
00262     return 0;
00263 }
00264 
00265 
00273 static void add_descriptor_to_list(pst_desc_ll *node, pst_desc_ll **head, pst_desc_ll **tail);
00274 static void add_descriptor_to_list(pst_desc_ll *node, pst_desc_ll **head, pst_desc_ll **tail)
00275 {
00276     DEBUG_ENT("add_descriptor_to_list");
00277     //DEBUG_INDEX(("Added node %#"PRIx64" parent %#"PRIx64" real parent %#"PRIx64" prev %#"PRIx64" next %#"PRIx64"\n",
00278     //             node->id, node->parent_d_id,
00279     //             (node->parent ? node->parent->id : (uint64_t)0),
00280     //             (node->prev   ? node->prev->id   : (uint64_t)0),
00281     //             (node->next   ? node->next->id   : (uint64_t)0)));
00282     if (*tail) (*tail)->next = node;
00283     if (!(*head)) *head = node;
00284     node->prev = *tail;
00285     node->next = NULL;
00286     *tail = node;
00287     DEBUG_RET();
00288 }
00289 
00290 
00297 static void record_descriptor(pst_file *pf, pst_desc_ll *node);
00298 static void record_descriptor(pst_file *pf, pst_desc_ll *node)
00299 {
00300     DEBUG_ENT("record_descriptor");
00301     // finish node initialization
00302     node->parent     = NULL;
00303     node->child      = NULL;
00304     node->child_tail = NULL;
00305     node->no_child   = 0;
00306 
00307     // find any orphan children of this node, and collect them
00308     pst_desc_ll *n = pf->d_head;
00309     while (n) {
00310         if (n->parent_d_id == node->d_id) {
00311             // found a child of this node
00312             DEBUG_INDEX(("Found orphan child %#"PRIx64" of parent %#"PRIx64"\n", n->d_id, node->d_id));
00313             pst_desc_ll *nn = n->next;
00314             pst_desc_ll *pp = n->prev;
00315             node->no_child++;
00316             n->parent = node;
00317             add_descriptor_to_list(n, &node->child, &node->child_tail);
00318             if (pp) pp->next = nn; else pf->d_head = nn;
00319             if (nn) nn->prev = pp; else pf->d_tail = pp;
00320             n = nn;
00321         }
00322         else {
00323             n = n->next;
00324         }
00325     }
00326 
00327     // now hook this node into the global tree
00328     if (node->parent_d_id == 0) {
00329         // add top level node to the descriptor tree
00330         //DEBUG_INDEX(("Null parent\n"));
00331         add_descriptor_to_list(node, &pf->d_head, &pf->d_tail);
00332     }
00333     else if (node->parent_d_id == node->d_id) {
00334         // add top level node to the descriptor tree
00335         DEBUG_INDEX(("%#"PRIx64" is its own parent. What is this world coming to?\n"));
00336         add_descriptor_to_list(node, &pf->d_head, &pf->d_tail);
00337     } else {
00338         //DEBUG_INDEX(("Searching for parent %#"PRIx64" of %#"PRIx64"\n", node->parent_d_id, node->d_id));
00339         pst_desc_ll *parent = pst_getDptr(pf, node->parent_d_id);
00340         if (parent) {
00341             //DEBUG_INDEX(("Found parent %#"PRIx64"\n", node->parent_d_id));
00342             parent->no_child++;
00343             node->parent = parent;
00344             add_descriptor_to_list(node, &parent->child, &parent->child_tail);
00345         }
00346         else {
00347             DEBUG_INDEX(("No parent %#"PRIx64", have an orphan child %#"PRIx64"\n", node->parent_d_id, node->d_id));
00348             add_descriptor_to_list(node, &pf->d_head, &pf->d_tail);
00349         }
00350     }
00351     DEBUG_RET();
00352 }
00353 
00354 
00362 static pst_id2_ll* deep_copy(pst_id2_ll *head);
00363 static pst_id2_ll* deep_copy(pst_id2_ll *head)
00364 {
00365     if (!head) return NULL;
00366     pst_id2_ll* me = (pst_id2_ll*) xmalloc(sizeof(pst_id2_ll));
00367     me->id2 = head->id2;
00368     me->id  = head->id;
00369     me->child = deep_copy(head->child);
00370     me->next  = deep_copy(head->next);
00371     return me;
00372 }
00373 
00374 
00375 pst_desc_ll* pst_getTopOfFolders(pst_file *pf, pst_item *root) {
00376     pst_desc_ll *topnode;
00377     uint32_t topid;
00378     DEBUG_ENT("pst_getTopOfFolders");
00379     if (!root || !root->message_store) {
00380         DEBUG_INDEX(("There isn't a top of folder record here.\n"));
00381         DEBUG_RET();
00382         return NULL;
00383     }
00384     if (!root->message_store->top_of_personal_folder) {
00385         // this is the OST way
00386         // ASSUMPTION: Top Of Folders record in PST files is *always* descid 0x2142
00387         topid = 0x2142;
00388     } else {
00389         topid = root->message_store->top_of_personal_folder->id;
00390     }
00391     DEBUG_INDEX(("looking for top of folder descriptor %#"PRIx32"\n", topid));
00392     topnode = pst_getDptr(pf, (uint64_t)topid);
00393     if (!topnode) {
00394         // add dummy top record to pickup orphan children
00395         topnode              = (pst_desc_ll*) xmalloc(sizeof(pst_desc_ll));
00396         topnode->d_id        = topid;
00397         topnode->parent_d_id = 0;
00398         topnode->assoc_tree  = NULL;
00399         topnode->desc        = NULL;
00400         record_descriptor(pf, topnode);   // add to the global tree
00401     }
00402     DEBUG_RET();
00403     return topnode;
00404 }
00405 
00406 
00407 size_t pst_attach_to_mem(pst_file *pf, pst_item_attach *attach, char **b){
00408     size_t size=0;
00409     pst_index_ll *ptr;
00410     pst_holder h = {b, NULL, 0};
00411     DEBUG_ENT("pst_attach_to_mem");
00412     if (attach->i_id != (uint64_t)-1) {
00413         ptr = pst_getID(pf, attach->i_id);
00414         if (ptr) {
00415             size = pst_ff_getID2data(pf, ptr, &h);
00416         } else {
00417             DEBUG_WARN(("Couldn't find ID pointer. Cannot handle attachment\n"));
00418             size = 0;
00419         }
00420         attach->data.size = size;
00421     } else {
00422         size = attach->data.size;
00423     }
00424     DEBUG_RET();
00425     return size;
00426 }
00427 
00428 
00429 size_t pst_attach_to_file(pst_file *pf, pst_item_attach *attach, FILE* fp) {
00430     pst_index_ll *ptr;
00431     pst_holder h = {NULL, fp, 0};
00432     size_t size = 0;
00433     DEBUG_ENT("pst_attach_to_file");
00434     if (attach->i_id != (uint64_t)-1) {
00435         ptr = pst_getID(pf, attach->i_id);
00436         if (ptr) {
00437             size = pst_ff_getID2data(pf, ptr, &h);
00438         } else {
00439             DEBUG_WARN(("Couldn't find ID pointer. Cannot save attachment to file\n"));
00440         }
00441         attach->data.size = size;
00442     } else {
00443         // save the attachment to the file
00444         size = attach->data.size;
00445         (void)pst_fwrite(attach->data.data, (size_t)1, size, fp);
00446     }
00447     DEBUG_RET();
00448     return size;
00449 }
00450 
00451 
00452 size_t pst_attach_to_file_base64(pst_file *pf, pst_item_attach *attach, FILE* fp) {
00453     pst_index_ll *ptr;
00454     pst_holder h = {NULL, fp, 1};
00455     size_t size = 0;
00456     DEBUG_ENT("pst_attach_to_file_base64");
00457     if (attach->i_id != (uint64_t)-1) {
00458         ptr = pst_getID(pf, attach->i_id);
00459         if (ptr) {
00460             size = pst_ff_getID2data(pf, ptr, &h);
00461         } else {
00462             DEBUG_WARN(("Couldn't find ID pointer. Cannot save attachment to Base64\n"));
00463         }
00464         attach->data.size = size;
00465     } else {
00466         // encode the attachment to the file
00467         char *c = base64_encode(attach->data.data, attach->data.size);
00468         if (c) {
00469             (void)pst_fwrite(c, (size_t)1, strlen(c), fp);
00470             free(c);    // caught by valgrind
00471         }
00472         size = attach->data.size;
00473     }
00474     DEBUG_RET();
00475     return size;
00476 }
00477 
00478 
00479 int pst_load_index (pst_file *pf) {
00480     int  x;
00481     DEBUG_ENT("pst_load_index");
00482     if (!pf) {
00483         WARN(("Cannot load index for a NULL pst_file\n"));
00484         DEBUG_RET();
00485         return -1;
00486     }
00487 
00488     x = pst_build_id_ptr(pf, pf->index1, 0, pf->index1_back, 0, UINT64_MAX);
00489     DEBUG_INDEX(("build id ptr returns %i\n", x));
00490 
00491     x = pst_build_desc_ptr(pf, pf->index2, 0, pf->index2_back, (uint64_t)0x21, UINT64_MAX);
00492     DEBUG_INDEX(("build desc ptr returns %i\n", x));
00493 
00494     DEBUG_CODE((void)pst_printDptr(pf, pf->d_head););
00495     DEBUG_RET();
00496     return 0;
00497 }
00498 
00499 
00500 pst_desc_ll* pst_getNextDptr(pst_desc_ll* d) {
00501     pst_desc_ll* r = NULL;
00502     DEBUG_ENT("pst_getNextDptr");
00503     if (d) {
00504         if ((r = d->child) == NULL) {
00505             while (!d->next && d->parent) d = d->parent;
00506             r = d->next;
00507         }
00508     }
00509     DEBUG_RET();
00510     return r;
00511 }
00512 
00513 
00514 typedef struct pst_x_attrib {
00515     uint32_t extended;
00516     uint16_t type;
00517     uint16_t map;
00518 } pst_x_attrib;
00519 
00520 
00521 int pst_load_extended_attributes(pst_file *pf) {
00522     // for PST files this will load up ID2 0x61 and check it's "list" attribute.
00523     pst_desc_ll *p;
00524     pst_mapi_object *na;
00525     pst_id2_ll *id2_head = NULL;
00526     char *buffer=NULL, *headerbuffer=NULL;
00527     size_t bsize=0, hsize=0, bptr=0;
00528     pst_x_attrib xattrib;
00529     int32_t tint, err=0, x;
00530     pst_x_attrib_ll *ptr, *p_head=NULL, *p_sh=NULL, *p_sh2=NULL;
00531 
00532     DEBUG_ENT("pst_loadExtendedAttributes");
00533     p = pst_getDptr(pf, (uint64_t)0x61);
00534     if (!p) {
00535         DEBUG_WARN(("Cannot find DescID 0x61 for loading the Extended Attributes\n"));
00536         DEBUG_RET();
00537         return 0;
00538     }
00539 
00540     if (!p->desc) {
00541         DEBUG_WARN(("desc is NULL for item 0x61. Cannot load Extended Attributes\n"));
00542         DEBUG_RET();
00543         return 0;
00544     }
00545 
00546     if (p->assoc_tree) {
00547         id2_head = pst_build_id2(pf, p->assoc_tree);
00548         pst_printID2ptr(id2_head);
00549     } else {
00550         DEBUG_WARN(("Have not been able to fetch any id2 values for item 0x61. Brace yourself!\n"));
00551     }
00552 
00553     na = pst_parse_block(pf, p->desc->i_id, id2_head);
00554     if (!na) {
00555         DEBUG_WARN(("Cannot process desc block for item 0x61. Not loading extended Attributes\n"));
00556         pst_free_id2(id2_head);
00557         DEBUG_RET();
00558         return 0;
00559     }
00560 
00561     for (x=0; x < na->count_elements; x++) {
00562         if (na->elements[x]->mapi_id == (uint32_t)0x0003) {
00563             buffer = na->elements[x]->data;
00564             bsize = na->elements[x]->size;
00565         } else if (na->elements[x]->mapi_id == (uint32_t)0x0004) {
00566             headerbuffer = na->elements[x]->data;
00567             hsize = na->elements[x]->size;
00568         } else {
00569             // leave them null
00570         }
00571     }
00572 
00573     if (!buffer) {
00574         pst_free_list(na);
00575         DEBUG_WARN(("No extended attributes buffer found. Not processing\n"));
00576         DEBUG_RET();
00577         return 0;
00578     }
00579 
00580     xattrib.extended= PST_LE_GET_UINT32(buffer+bptr), bptr += 4;
00581     xattrib.type    = PST_LE_GET_UINT16(buffer+bptr), bptr += 2;
00582     xattrib.map     = PST_LE_GET_UINT16(buffer+bptr), bptr += 2;
00583 
00584     while (xattrib.type != 0 && bptr < bsize) {
00585         ptr = (pst_x_attrib_ll*) xmalloc(sizeof(*ptr));
00586         memset(ptr, 0, sizeof(*ptr));
00587         ptr->type = xattrib.type;
00588         ptr->map  = xattrib.map+0x8000;
00589         ptr->next = NULL;
00590         DEBUG_INDEX(("xattrib: ext = %#x, type = %#hx, map = %#hx\n",
00591              xattrib.extended, xattrib.type, xattrib.map));
00592         err=0;
00593         if (xattrib.type & 0x0001) { // if the Bit 1 is set
00594             // pointer to Unicode field in buffer
00595             if (xattrib.extended < hsize) {
00596                 char *wt;
00597                 // copy the size of the header. It is 32 bit int
00598                 memcpy(&tint, &(headerbuffer[xattrib.extended]), sizeof(tint));
00599                 LE32_CPU(tint);
00600                 wt = (char*) xmalloc((size_t)(tint+2)); // plus 2 for a uni-code zero
00601                 memset(wt, 0, (size_t)(tint+2));
00602                 memcpy(wt, &(headerbuffer[xattrib.extended+sizeof(tint)]), (size_t)tint);
00603                 ptr->data = pst_wide_to_single(wt, (size_t)tint);
00604                 free(wt);
00605                 DEBUG_INDEX(("Read string (converted from UTF-16): %s\n", ptr->data));
00606             } else {
00607                 DEBUG_INDEX(("Cannot read outside of buffer [%i !< %i]\n", xattrib.extended, hsize));
00608             }
00609             ptr->mytype = PST_MAP_HEADER;
00610         } else {
00611             // contains the attribute code to map to.
00612             ptr->data = (uint32_t*)xmalloc(sizeof(uint32_t));
00613             memset(ptr->data, 0, sizeof(uint32_t));
00614             *((uint32_t*)ptr->data) = xattrib.extended;
00615             ptr->mytype = PST_MAP_ATTRIB;
00616             DEBUG_INDEX(("Mapped attribute %#x to %#x\n", ptr->map, *((int32_t*)ptr->data)));
00617         }
00618 
00619         if (err==0) {
00620             // add it to the list
00621             p_sh = p_head;
00622             p_sh2 = NULL;
00623             while (p_sh && ptr->map > p_sh->map) {
00624                 p_sh2 = p_sh;
00625                 p_sh = p_sh->next;
00626             }
00627             if (!p_sh2) {
00628                 // needs to go before first item
00629                 ptr->next = p_head;
00630                 p_head = ptr;
00631             } else {
00632                 // it will go after p_sh2
00633                 ptr->next = p_sh2->next;
00634                 p_sh2->next = ptr;
00635             }
00636         } else {
00637             free(ptr);
00638             ptr = NULL;
00639         }
00640         memcpy(&xattrib, &(buffer[bptr]), sizeof(xattrib));
00641         LE32_CPU(xattrib.extended);
00642         LE16_CPU(xattrib.type);
00643         LE16_CPU(xattrib.map);
00644         bptr += sizeof(xattrib);
00645     }
00646     pst_free_id2(id2_head);
00647     pst_free_list(na);
00648     pf->x_head = p_head;
00649     DEBUG_RET();
00650     return 1;
00651 }
00652 
00653 
00654 #define ITEM_COUNT_OFFSET32        0x1f0    // count byte
00655 #define LEVEL_INDICATOR_OFFSET32   0x1f3    // node or leaf
00656 #define BACKLINK_OFFSET32          0x1f8    // backlink u1 value
00657 #define ITEM_SIZE32                12
00658 #define DESC_SIZE32                16
00659 #define INDEX_COUNT_MAX32          41       // max active items
00660 #define DESC_COUNT_MAX32           31       // max active items
00661 
00662 #define ITEM_COUNT_OFFSET64        0x1e8    // count byte
00663 #define LEVEL_INDICATOR_OFFSET64   0x1eb    // node or leaf
00664 #define BACKLINK_OFFSET64          0x1f8    // backlink u1 value
00665 #define ITEM_SIZE64                24
00666 #define DESC_SIZE64                32
00667 #define INDEX_COUNT_MAX64          20       // max active items
00668 #define DESC_COUNT_MAX64           15       // max active items
00669 
00670 #define BLOCK_SIZE                 512      // index blocks
00671 #define DESC_BLOCK_SIZE            512      // descriptor blocks
00672 #define ITEM_COUNT_OFFSET        (size_t)((pf->do_read64) ? ITEM_COUNT_OFFSET64      : ITEM_COUNT_OFFSET32)
00673 #define LEVEL_INDICATOR_OFFSET   (size_t)((pf->do_read64) ? LEVEL_INDICATOR_OFFSET64 : LEVEL_INDICATOR_OFFSET32)
00674 #define BACKLINK_OFFSET          (size_t)((pf->do_read64) ? BACKLINK_OFFSET64        : BACKLINK_OFFSET32)
00675 #define ITEM_SIZE                (size_t)((pf->do_read64) ? ITEM_SIZE64              : ITEM_SIZE32)
00676 #define DESC_SIZE                (size_t)((pf->do_read64) ? DESC_SIZE64              : DESC_SIZE32)
00677 #define INDEX_COUNT_MAX         (int32_t)((pf->do_read64) ? INDEX_COUNT_MAX64        : INDEX_COUNT_MAX32)
00678 #define DESC_COUNT_MAX          (int32_t)((pf->do_read64) ? DESC_COUNT_MAX64         : DESC_COUNT_MAX32)
00679 
00680 
00681 static size_t pst_decode_desc(pst_file *pf, pst_descn *desc, char *buf);
00682 static size_t pst_decode_desc(pst_file *pf, pst_descn *desc, char *buf) {
00683     size_t r;
00684     if (pf->do_read64) {
00685         DEBUG_INDEX(("Decoding desc64\n"));
00686         DEBUG_HEXDUMPC(buf, sizeof(pst_descn), 0x10);
00687         memcpy(desc, buf, sizeof(pst_descn));
00688         LE64_CPU(desc->d_id);
00689         LE64_CPU(desc->desc_id);
00690         LE64_CPU(desc->tree_id);
00691         LE32_CPU(desc->parent_d_id);
00692         LE32_CPU(desc->u1);
00693         r = sizeof(pst_descn);
00694     }
00695     else {
00696         pst_desc32 d32;
00697         DEBUG_INDEX(("Decoding desc32\n"));
00698         DEBUG_HEXDUMPC(buf, sizeof(pst_desc32), 0x10);
00699         memcpy(&d32, buf, sizeof(pst_desc32));
00700         LE32_CPU(d32.d_id);
00701         LE32_CPU(d32.desc_id);
00702         LE32_CPU(d32.tree_id);
00703         LE32_CPU(d32.parent_d_id);
00704         desc->d_id        = d32.d_id;
00705         desc->desc_id     = d32.desc_id;
00706         desc->tree_id     = d32.tree_id;
00707         desc->parent_d_id = d32.parent_d_id;
00708         desc->u1          = 0;
00709         r = sizeof(pst_desc32);
00710     }
00711     return r;
00712 }
00713 
00714 
00715 static size_t pst_decode_table(pst_file *pf, struct pst_table_ptr_structn *table, char *buf);
00716 static size_t pst_decode_table(pst_file *pf, struct pst_table_ptr_structn *table, char *buf) {
00717     size_t r;
00718     if (pf->do_read64) {
00719         DEBUG_INDEX(("Decoding table64\n"));
00720         DEBUG_HEXDUMPC(buf, sizeof(struct pst_table_ptr_structn), 0x10);
00721         memcpy(table, buf, sizeof(struct pst_table_ptr_structn));
00722         LE64_CPU(table->start);
00723         LE64_CPU(table->u1);
00724         LE64_CPU(table->offset);
00725         r =sizeof(struct pst_table_ptr_structn);
00726     }
00727     else {
00728         struct pst_table_ptr_struct32 t32;
00729         DEBUG_INDEX(("Decoding table32\n"));
00730         DEBUG_HEXDUMPC(buf, sizeof( struct pst_table_ptr_struct32), 0x10);
00731         memcpy(&t32, buf, sizeof(struct pst_table_ptr_struct32));
00732         LE32_CPU(t32.start);
00733         LE32_CPU(t32.u1);
00734         LE32_CPU(t32.offset);
00735         table->start  = t32.start;
00736         table->u1     = t32.u1;
00737         table->offset = t32.offset;
00738         r = sizeof(struct pst_table_ptr_struct32);
00739     }
00740     return r;
00741 }
00742 
00743 
00744 static size_t pst_decode_index(pst_file *pf, pst_index *index, char *buf);
00745 static size_t pst_decode_index(pst_file *pf, pst_index *index, char *buf) {
00746     size_t r;
00747     if (pf->do_read64) {
00748         DEBUG_INDEX(("Decoding index64\n"));
00749         DEBUG_HEXDUMPC(buf, sizeof(pst_index), 0x10);
00750         memcpy(index, buf, sizeof(pst_index));
00751         LE64_CPU(index->id);
00752         LE64_CPU(index->offset);
00753         LE16_CPU(index->size);
00754         LE16_CPU(index->u0);
00755         LE32_CPU(index->u1);
00756         r = sizeof(pst_index);
00757     } else {
00758         pst_index32 index32;
00759         DEBUG_INDEX(("Decoding index32\n"));
00760         DEBUG_HEXDUMPC(buf, sizeof(pst_index32), 0x10);
00761         memcpy(&index32, buf, sizeof(pst_index32));
00762         LE32_CPU(index32.id);
00763         LE32_CPU(index32.offset);
00764         LE16_CPU(index32.size);
00765         LE16_CPU(index32.u1);
00766         index->id     = index32.id;
00767         index->offset = index32.offset;
00768         index->size   = index32.size;
00769         index->u0     = 0;
00770         index->u1     = index32.u1;
00771         r = sizeof(pst_index32);
00772     }
00773     return r;
00774 }
00775 
00776 
00777 static size_t pst_decode_assoc(pst_file *pf, pst_id2_assoc *assoc, char *buf);
00778 static size_t pst_decode_assoc(pst_file *pf, pst_id2_assoc *assoc, char *buf) {
00779     size_t r;
00780     if (pf->do_read64) {
00781         DEBUG_INDEX(("Decoding assoc64\n"));
00782         DEBUG_HEXDUMPC(buf, sizeof(pst_id2_assoc), 0x10);
00783         memcpy(assoc, buf, sizeof(pst_id2_assoc));
00784         LE32_CPU(assoc->id2);
00785         LE64_CPU(assoc->id);
00786         LE64_CPU(assoc->child_id);
00787         r = sizeof(pst_id2_assoc);
00788     } else {
00789         pst_id2_assoc32 assoc32;
00790         DEBUG_INDEX(("Decoding assoc32\n"));
00791         DEBUG_HEXDUMPC(buf, sizeof(pst_id2_assoc32), 0x10);
00792         memcpy(&assoc32, buf, sizeof(pst_id2_assoc32));
00793         LE32_CPU(assoc32.id2);
00794         LE32_CPU(assoc32.id);
00795         LE32_CPU(assoc32.child_id);
00796         assoc->id2      = assoc32.id2;
00797         assoc->id       = assoc32.id;
00798         assoc->child_id = assoc32.child_id;
00799         r = sizeof(pst_id2_assoc32);
00800     }
00801     return r;
00802 }
00803 
00804 
00805 static size_t pst_decode_type3(pst_file *pf, pst_table3_rec *table3_rec, char *buf);
00806 static size_t pst_decode_type3(pst_file *pf, pst_table3_rec *table3_rec, char *buf) {
00807     size_t r;
00808     if (pf->do_read64) {
00809         DEBUG_INDEX(("Decoding table3 64\n"));
00810         DEBUG_HEXDUMPC(buf, sizeof(pst_table3_rec), 0x10);
00811         memcpy(table3_rec, buf, sizeof(pst_table3_rec));
00812         LE64_CPU(table3_rec->id);
00813         r = sizeof(pst_table3_rec);
00814     } else {
00815         pst_table3_rec32 table3_rec32;
00816         DEBUG_INDEX(("Decoding table3 32\n"));
00817         DEBUG_HEXDUMPC(buf, sizeof(pst_table3_rec32), 0x10);
00818         memcpy(&table3_rec32, buf, sizeof(pst_table3_rec32));
00819         LE32_CPU(table3_rec32.id);
00820         table3_rec->id  = table3_rec32.id;
00821         r = sizeof(pst_table3_rec32);
00822     }
00823     return r;
00824 }
00825 
00826 
00832 int pst_build_id_ptr(pst_file *pf, int64_t offset, int32_t depth, uint64_t linku1, uint64_t start_val, uint64_t end_val) {
00833     struct pst_table_ptr_structn table, table2;
00834     pst_index_ll *i_ptr=NULL;
00835     pst_index index;
00836     int32_t x, item_count;
00837     uint64_t old = start_val;
00838     char *buf = NULL, *bptr;
00839 
00840     DEBUG_ENT("pst_build_id_ptr");
00841     DEBUG_INDEX(("offset %#"PRIx64" depth %i linku1 %#"PRIx64" start %#"PRIx64" end %#"PRIx64"\n", offset, depth, linku1, start_val, end_val));
00842     if (end_val <= start_val) {
00843         DEBUG_WARN(("The end value is BEFORE the start value. This function will quit. Soz. [start:%#"PRIx64", end:%#"PRIx64"]\n", start_val, end_val));
00844         DEBUG_RET();
00845         return -1;
00846     }
00847     DEBUG_INDEX(("Reading index block\n"));
00848     if (pst_read_block_size(pf, offset, BLOCK_SIZE, &buf) < BLOCK_SIZE) {
00849         DEBUG_WARN(("Failed to read %i bytes\n", BLOCK_SIZE));
00850         if (buf) free(buf);
00851         DEBUG_RET();
00852         return -1;
00853     }
00854     bptr = buf;
00855     DEBUG_HEXDUMPC(buf, BLOCK_SIZE, ITEM_SIZE32);
00856     item_count = (int32_t)(unsigned)(buf[ITEM_COUNT_OFFSET]);
00857     if (item_count > INDEX_COUNT_MAX) {
00858         DEBUG_WARN(("Item count %i too large, max is %i\n", item_count, INDEX_COUNT_MAX));
00859         if (buf) free(buf);
00860         DEBUG_RET();
00861         return -1;
00862     }
00863     index.id = pst_getIntAt(pf, buf+BACKLINK_OFFSET);
00864     if (index.id != linku1) {
00865         DEBUG_WARN(("Backlink %#"PRIx64" in this node does not match required %#"PRIx64"\n", index.id, linku1));
00866         if (buf) free(buf);
00867         DEBUG_RET();
00868         return -1;
00869     }
00870 
00871     if (buf[LEVEL_INDICATOR_OFFSET] == '\0') {
00872         // this node contains leaf pointers
00873         x = 0;
00874         while (x < item_count) {
00875             bptr += pst_decode_index(pf, &index, bptr);
00876             x++;
00877             if (index.id == 0) break;
00878             DEBUG_INDEX(("[%i]%i Item [id = %#"PRIx64", offset = %#"PRIx64", u1 = %#x, size = %i(%#x)]\n",
00879                         depth, x, index.id, index.offset, index.u1, index.size, index.size));
00880             // if (index.id & 0x02) DEBUG_INDEX(("two-bit set!!\n"));
00881             if ((index.id >= end_val) || (index.id < old)) {
00882                 DEBUG_WARN(("This item isn't right. Must be corruption, or I got it wrong!\n"));
00883                 if (buf) free(buf);
00884                 DEBUG_RET();
00885                 return -1;
00886             }
00887             old = index.id;
00888             if (x == (int32_t)1) {   // first entry
00889                 if ((start_val) && (index.id != start_val)) {
00890                     DEBUG_WARN(("This item isn't right. Must be corruption, or I got it wrong!\n"));
00891                     if (buf) free(buf);
00892                     DEBUG_RET();
00893                     return -1;
00894                 }
00895             }
00896             i_ptr = (pst_index_ll*) xmalloc(sizeof(pst_index_ll));
00897             i_ptr->i_id   = index.id;
00898             i_ptr->offset = index.offset;
00899             i_ptr->u1     = index.u1;
00900             i_ptr->size   = index.size;
00901             i_ptr->next   = NULL;
00902             if (pf->i_tail)  pf->i_tail->next = i_ptr;
00903             if (!pf->i_head) pf->i_head = i_ptr;
00904             pf->i_tail = i_ptr;
00905         }
00906     } else {
00907         // this node contains node pointers
00908         x = 0;
00909         while (x < item_count) {
00910             bptr += pst_decode_table(pf, &table, bptr);
00911             x++;
00912             if (table.start == 0) break;
00913             if (x < item_count) {
00914                 (void)pst_decode_table(pf, &table2, bptr);
00915             }
00916             else {
00917                 table2.start = end_val;
00918             }
00919             DEBUG_INDEX(("[%i] %i Index Table [start id = %#"PRIx64", u1 = %#"PRIx64", offset = %#"PRIx64", end id = %#"PRIx64"]\n",
00920                         depth, x, table.start, table.u1, table.offset, table2.start));
00921             if ((table.start >= end_val) || (table.start < old)) {
00922                 DEBUG_WARN(("This table isn't right. Must be corruption, or I got it wrong!\n"));
00923                 if (buf) free(buf);
00924                 DEBUG_RET();
00925                 return -1;
00926             }
00927             old = table.start;
00928             if (x == (int32_t)1) {  // first entry
00929                 if ((start_val) && (table.start != start_val)) {
00930                     DEBUG_WARN(("This table isn't right. Must be corruption, or I got it wrong!\n"));
00931                     if (buf) free(buf);
00932                     DEBUG_RET();
00933                     return -1;
00934                 }
00935             }
00936             (void)pst_build_id_ptr(pf, table.offset, depth+1, table.u1, table.start, table2.start);
00937         }
00938     }
00939     if (buf) free (buf);
00940     DEBUG_RET();
00941     return 0;
00942 }
00943 
00944 
00949 int pst_build_desc_ptr (pst_file *pf, int64_t offset, int32_t depth, uint64_t linku1, uint64_t start_val, uint64_t end_val) {
00950     struct pst_table_ptr_structn table, table2;
00951     pst_descn desc_rec;
00952     int32_t item_count;
00953     uint64_t old = start_val;
00954     int x;
00955     char *buf = NULL, *bptr;
00956 
00957     DEBUG_ENT("pst_build_desc_ptr");
00958     DEBUG_INDEX(("offset %#"PRIx64" depth %i linku1 %#"PRIx64" start %#"PRIx64" end %#"PRIx64"\n", offset, depth, linku1, start_val, end_val));
00959     if (end_val <= start_val) {
00960         DEBUG_WARN(("The end value is BEFORE the start value. This function will quit. Soz. [start:%#"PRIx64", end:%#"PRIx64"]\n", start_val, end_val));
00961         DEBUG_RET();
00962         return -1;
00963     }
00964     DEBUG_INDEX(("Reading desc block\n"));
00965     if (pst_read_block_size(pf, offset, DESC_BLOCK_SIZE, &buf) < DESC_BLOCK_SIZE) {
00966         DEBUG_WARN(("Failed to read %i bytes\n", DESC_BLOCK_SIZE));
00967         if (buf) free(buf);
00968         DEBUG_RET();
00969         return -1;
00970     }
00971     bptr = buf;
00972     item_count = (int32_t)(unsigned)(buf[ITEM_COUNT_OFFSET]);
00973 
00974     desc_rec.d_id = pst_getIntAt(pf, buf+BACKLINK_OFFSET);
00975     if (desc_rec.d_id != linku1) {
00976         DEBUG_WARN(("Backlink %#"PRIx64" in this node does not match required %#"PRIx64"\n", desc_rec.d_id, linku1));
00977         if (buf) free(buf);
00978         DEBUG_RET();
00979         return -1;
00980     }
00981     if (buf[LEVEL_INDICATOR_OFFSET] == '\0') {
00982         // this node contains leaf pointers
00983         DEBUG_HEXDUMPC(buf, DESC_BLOCK_SIZE, DESC_SIZE32);
00984         if (item_count > DESC_COUNT_MAX) {
00985             DEBUG_WARN(("Item count %i too large, max is %i\n", item_count, DESC_COUNT_MAX));
00986             if (buf) free(buf);
00987             DEBUG_RET();
00988             return -1;
00989         }
00990         for (x=0; x<item_count; x++) {
00991             bptr += pst_decode_desc(pf, &desc_rec, bptr);
00992             DEBUG_INDEX(("[%i] Item(%#x) = [d_id = %#"PRIx64", desc_id = %#"PRIx64", tree_id = %#"PRIx64", parent_d_id = %#x]\n",
00993                         depth, x, desc_rec.d_id, desc_rec.desc_id, desc_rec.tree_id, desc_rec.parent_d_id));
00994             if ((desc_rec.d_id >= end_val) || (desc_rec.d_id < old)) {
00995                 DEBUG_WARN(("This item isn't right. Must be corruption, or I got it wrong!\n"));
00996                 DEBUG_HEXDUMPC(buf, DESC_BLOCK_SIZE, 16);
00997                 if (buf) free(buf);
00998                 DEBUG_RET();
00999                 return -1;
01000             }
01001             old = desc_rec.d_id;
01002             if (x == 0) {   // first entry
01003                 if (start_val && (desc_rec.d_id != start_val)) {
01004                     DEBUG_WARN(("This item isn't right. Must be corruption, or I got it wrong!\n"));
01005                     if (buf) free(buf);
01006                     DEBUG_RET();
01007                     return -1;
01008                 }
01009             }
01010             DEBUG_INDEX(("New Record %#"PRIx64" with parent %#x\n", desc_rec.d_id, desc_rec.parent_d_id));
01011             {
01012                 pst_desc_ll *d_ptr = (pst_desc_ll*) xmalloc(sizeof(pst_desc_ll));
01013                 d_ptr->d_id        = desc_rec.d_id;
01014                 d_ptr->parent_d_id = desc_rec.parent_d_id;
01015                 d_ptr->assoc_tree  = pst_getID(pf, desc_rec.tree_id);
01016                 d_ptr->desc        = pst_getID(pf, desc_rec.desc_id);
01017                 record_descriptor(pf, d_ptr);   // add to the global tree
01018             }
01019         }
01020     } else {
01021         // this node contains node pointers
01022         DEBUG_HEXDUMPC(buf, DESC_BLOCK_SIZE, ITEM_SIZE32);
01023         if (item_count > INDEX_COUNT_MAX) {
01024             DEBUG_WARN(("Item count %i too large, max is %i\n", item_count, INDEX_COUNT_MAX));
01025             if (buf) free(buf);
01026             DEBUG_RET();
01027             return -1;
01028         }
01029         for (x=0; x<item_count; x++) {
01030             bptr += pst_decode_table(pf, &table, bptr);
01031             if (table.start == 0) break;
01032             if (x < (item_count-1)) {
01033                 (void)pst_decode_table(pf, &table2, bptr);
01034             }
01035             else {
01036                 table2.start = end_val;
01037             }
01038             DEBUG_INDEX(("[%i] %i Descriptor Table [start id = %#"PRIx64", u1 = %#"PRIx64", offset = %#"PRIx64", end id = %#"PRIx64"]\n",
01039                         depth, x, table.start, table.u1, table.offset, table2.start));
01040             if ((table.start >= end_val) || (table.start < old)) {
01041                 DEBUG_WARN(("This table isn't right. Must be corruption, or I got it wrong!\n"));
01042                 if (buf) free(buf);
01043                 DEBUG_RET();
01044                 return -1;
01045             }
01046             old = table.start;
01047             if (x == 0) {   // first entry
01048                 if (start_val && (table.start != start_val)) {
01049                     DEBUG_WARN(("This table isn't right. Must be corruption, or I got it wrong!\n"));
01050                     if (buf) free(buf);
01051                     DEBUG_RET();
01052                     return -1;
01053                 }
01054             }
01055             (void)pst_build_desc_ptr(pf, table.offset, depth+1, table.u1, table.start, table2.start);
01056         }
01057     }
01058     if (buf) free(buf);
01059     DEBUG_RET();
01060     return 0;
01061 }
01062 
01063 
01066 pst_item* pst_parse_item(pst_file *pf, pst_desc_ll *d_ptr, pst_id2_ll *m_head) {
01067     pst_mapi_object * list;
01068     pst_id2_ll *id2_head = m_head;
01069     pst_id2_ll *id2_ptr  = NULL;
01070     pst_item *item = NULL;
01071     pst_item_attach *attach = NULL;
01072     int32_t x;
01073     DEBUG_ENT("pst_parse_item");
01074     if (!d_ptr) {
01075         DEBUG_WARN(("you cannot pass me a NULL! I don't want it!\n"));
01076         DEBUG_RET();
01077         return NULL;
01078     }
01079 
01080     if (!d_ptr->desc) {
01081         DEBUG_WARN(("why is d_ptr->desc == NULL? I don't want to do anything else with this record\n"));
01082         DEBUG_RET();
01083         return NULL;
01084     }
01085 
01086     if (d_ptr->assoc_tree) {
01087         if (m_head) {
01088             DEBUG_WARN(("supplied master head, but have a list that is building a new id2_head"));
01089             m_head = NULL;
01090         }
01091         id2_head = pst_build_id2(pf, d_ptr->assoc_tree);
01092     }
01093     pst_printID2ptr(id2_head);
01094 
01095     list = pst_parse_block(pf, d_ptr->desc->i_id, id2_head);
01096     if (!list) {
01097         DEBUG_WARN(("pst_parse_block() returned an error for d_ptr->desc->i_id [%#"PRIx64"]\n", d_ptr->desc->i_id));
01098         if (!m_head) pst_free_id2(id2_head);
01099         DEBUG_RET();
01100         return NULL;
01101     }
01102 
01103     item = (pst_item*) xmalloc(sizeof(pst_item));
01104     memset(item, 0, sizeof(pst_item));
01105 
01106     if (pst_process(list, item, NULL)) {
01107         DEBUG_WARN(("pst_process() returned non-zero value. That is an error\n"));
01108         pst_freeItem(item);
01109         pst_free_list(list);
01110         if (!m_head) pst_free_id2(id2_head);
01111         DEBUG_RET();
01112         return NULL;
01113     }
01114     pst_free_list(list);
01115 
01116     if ((id2_ptr = pst_getID2(id2_head, (uint64_t)0x692))) {
01117         // DSN/MDN reports?
01118         DEBUG_EMAIL(("DSN/MDN processing\n"));
01119         list = pst_parse_block(pf, id2_ptr->id->i_id, id2_head);
01120         if (!list) {
01121             DEBUG_WARN(("ERROR error processing main DSN/MDN record\n"));
01122             if (!m_head) pst_free_id2(id2_head);
01123             DEBUG_RET();
01124             return item;
01125         }
01126         for (x=0; x < list->count_objects; x++) {
01127             attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach));
01128             memset(attach, 0, sizeof(pst_item_attach));
01129             attach->next = item->attach;
01130             item->attach = attach;
01131         }
01132         if (pst_process(list, item, item->attach)) {
01133             DEBUG_WARN(("ERROR pst_process() failed with DSN/MDN attachments\n"));
01134             pst_freeItem(item);
01135             pst_free_list(list);
01136             if (!m_head) pst_free_id2(id2_head);
01137             DEBUG_RET();
01138             return NULL;
01139         }
01140         pst_free_list(list);
01141     }
01142 
01143     if ((id2_ptr = pst_getID2(id2_head, (uint64_t)0x671))) {
01144         DEBUG_EMAIL(("ATTACHMENT processing attachment\n"));
01145         list = pst_parse_block(pf, id2_ptr->id->i_id, id2_head);
01146         if (!list) {
01147             DEBUG_WARN(("ERROR error processing main attachment record\n"));
01148             if (!m_head) pst_free_id2(id2_head);
01149             DEBUG_RET();
01150             return item;
01151         }
01152         for (x=0; x < list->count_objects; x++) {
01153             attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach));
01154             memset(attach, 0, sizeof(pst_item_attach));
01155             attach->next = item->attach;
01156             item->attach = attach;
01157         }
01158         if (pst_process(list, item, item->attach)) {
01159             DEBUG_WARN(("ERROR pst_process() failed with attachments\n"));
01160             pst_freeItem(item);
01161             pst_free_list(list);
01162             if (!m_head) pst_free_id2(id2_head);
01163             DEBUG_RET();
01164             return NULL;
01165         }
01166         pst_free_list(list);
01167 
01168         // now we will have initial information of each attachment stored in item->attach...
01169         // we must now read the secondary record for each based on the id2 val associated with
01170         // each attachment
01171         attach = item->attach;
01172         while (attach) {
01173             DEBUG_WARN(("initial attachment id2 %#"PRIx64"\n", attach->id2_val));
01174             if ((id2_ptr = pst_getID2(id2_head, attach->id2_val))) {
01175                 DEBUG_WARN(("initial attachment id2 found id %#"PRIx64"\n", id2_ptr->id->i_id));
01176                 // id_ptr is a record describing the attachment
01177                 // we pass NULL instead of id2_head cause we don't want it to
01178                 // load all the extra stuff here.
01179                 list = pst_parse_block(pf, id2_ptr->id->i_id, NULL);
01180                 if (!list) {
01181                     DEBUG_WARN(("ERROR error processing an attachment record\n"));
01182                     attach = attach->next;
01183                     continue;
01184                 }
01185                 if (list->count_objects > 1) {
01186                     DEBUG_WARN(("ERROR probably fatal, list count array will overrun attach structure.\n"));
01187                 }
01188                 if (pst_process(list, item, attach)) {
01189                     DEBUG_WARN(("ERROR pst_process() failed with an attachment\n"));
01190                     pst_free_list(list);
01191                     attach = attach->next;
01192                     continue;
01193                 }
01194                 pst_free_list(list);
01195                 id2_ptr = pst_getID2(id2_head, attach->id2_val);
01196                 if (id2_ptr) {
01197                     DEBUG_WARN(("second pass attachment updating id2 found i_id %#"PRIx64"\n", id2_ptr->id->i_id));
01198                     // id2_val has been updated to the ID2 value of the datablock containing the
01199                     // attachment data
01200                     attach->i_id     = id2_ptr->id->i_id;
01201                     attach->id2_head = deep_copy(id2_ptr->child);
01202                 } else {
01203                     DEBUG_WARN(("have not located the correct value for the attachment [%#"PRIx64"]\n", attach->id2_val));
01204                 }
01205             } else {
01206                 DEBUG_WARN(("ERROR cannot locate id2 value %#"PRIx64"\n", attach->id2_val));
01207                 attach->id2_val = 0;    // suppress this missing attachment
01208             }
01209             attach = attach->next;
01210         }
01211     }
01212 
01213     if (!m_head) pst_free_id2(id2_head);
01214     DEBUG_RET();
01215     return item;
01216 }
01217 
01218 
01219 static void freeall(pst_subblocks *subs, pst_block_offset_pointer *p1,
01220                                          pst_block_offset_pointer *p2,
01221                                          pst_block_offset_pointer *p3,
01222                                          pst_block_offset_pointer *p4,
01223                                          pst_block_offset_pointer *p5,
01224                                          pst_block_offset_pointer *p6,
01225                                          pst_block_offset_pointer *p7);
01226 static void freeall(pst_subblocks *subs, pst_block_offset_pointer *p1,
01227                                          pst_block_offset_pointer *p2,
01228                                          pst_block_offset_pointer *p3,
01229                                          pst_block_offset_pointer *p4,
01230                                          pst_block_offset_pointer *p5,
01231                                          pst_block_offset_pointer *p6,
01232                                          pst_block_offset_pointer *p7) {
01233     size_t i;
01234     for (i=0; i<subs->subblock_count; i++) {
01235         if (subs->subs[i].buf) free(subs->subs[i].buf);
01236     }
01237     free(subs->subs);
01238     if (p1->needfree) free(p1->from);
01239     if (p2->needfree) free(p2->from);
01240     if (p3->needfree) free(p3->from);
01241     if (p4->needfree) free(p4->from);
01242     if (p5->needfree) free(p5->from);
01243     if (p6->needfree) free(p6->from);
01244     if (p7->needfree) free(p7->from);
01245 }
01246 
01247 
01253 pst_mapi_object * pst_parse_block(pst_file *pf, uint64_t block_id, pst_id2_ll *i2_head) {
01254     pst_mapi_object *mo_head = NULL;
01255     char  *buf       = NULL;
01256     size_t read_size = 0;
01257     pst_subblocks  subblocks;
01258     pst_mapi_object *mo_ptr = NULL;
01259     pst_block_offset_pointer block_offset1;
01260     pst_block_offset_pointer block_offset2;
01261     pst_block_offset_pointer block_offset3;
01262     pst_block_offset_pointer block_offset4;
01263     pst_block_offset_pointer block_offset5;
01264     pst_block_offset_pointer block_offset6;
01265     pst_block_offset_pointer block_offset7;
01266     int32_t  x;
01267     int      num_recs;
01268     int      count_rec;
01269     int32_t  num_list;
01270     int32_t  cur_list;
01271     int      block_type;
01272     uint32_t rec_size = 0;
01273     char*    list_start;
01274     char*    fr_ptr;
01275     char*    to_ptr;
01276     char*    ind2_end = NULL;
01277     char*    ind2_ptr = NULL;
01278     pst_x_attrib_ll *mapptr;
01279     pst_block_hdr    block_hdr;
01280     pst_table3_rec   table3_rec;  //for type 3 (0x0101) blocks
01281 
01282     struct {
01283         unsigned char seven_c;
01284         unsigned char item_count;
01285         uint16_t u1;
01286         uint16_t u2;
01287         uint16_t u3;
01288         uint16_t rec_size;
01289         uint32_t b_five_offset;
01290         uint32_t ind2_offset;
01291         uint16_t u7;
01292         uint16_t u8;
01293     } seven_c_blk;
01294 
01295     struct _type_d_rec {
01296         uint32_t id;
01297         uint32_t u1;
01298     } * type_d_rec;
01299 
01300     struct {
01301         uint16_t type;
01302         uint16_t ref_type;
01303         uint32_t value;
01304     } table_rec;    //for type 1 (0xBCEC) blocks
01305 
01306     struct {
01307         uint16_t ref_type;
01308         uint16_t type;
01309         uint16_t ind2_off;
01310         uint8_t  size;
01311         uint8_t  slot;
01312     } table2_rec;   //for type 2 (0x7CEC) blocks
01313 
01314     DEBUG_ENT("pst_parse_block");
01315     if ((read_size = pst_ff_getIDblock_dec(pf, block_id, &buf)) == 0) {
01316         WARN(("Error reading block id %#"PRIx64"\n", block_id));
01317         if (buf) free (buf);
01318         DEBUG_RET();
01319         return NULL;
01320     }
01321 
01322     block_offset1.needfree = 0;
01323     block_offset2.needfree = 0;
01324     block_offset3.needfree = 0;
01325     block_offset4.needfree = 0;
01326     block_offset5.needfree = 0;
01327     block_offset6.needfree = 0;
01328     block_offset7.needfree = 0;
01329 
01330     memcpy(&block_hdr, buf, sizeof(block_hdr));
01331     LE16_CPU(block_hdr.index_offset);
01332     LE16_CPU(block_hdr.type);
01333     LE32_CPU(block_hdr.offset);
01334     DEBUG_EMAIL(("block header (index_offset=%#hx, type=%#hx, offset=%#hx)\n", block_hdr.index_offset, block_hdr.type, block_hdr.offset));
01335 
01336     if (block_hdr.index_offset == (uint16_t)0x0101) { //type 3
01337         size_t i;
01338         char *b_ptr = buf + 8;
01339         subblocks.subblock_count = block_hdr.type;
01340         subblocks.subs = malloc(sizeof(pst_subblock) * subblocks.subblock_count);
01341         for (i=0; i<subblocks.subblock_count; i++) {
01342             b_ptr += pst_decode_type3(pf, &table3_rec, b_ptr);
01343             subblocks.subs[i].buf       = NULL;
01344             subblocks.subs[i].read_size = pst_ff_getIDblock_dec(pf, table3_rec.id, &subblocks.subs[i].buf);
01345             if (subblocks.subs[i].buf) {
01346                 memcpy(&block_hdr, subblocks.subs[i].buf, sizeof(block_hdr));
01347                 LE16_CPU(block_hdr.index_offset);
01348                 subblocks.subs[i].i_offset = block_hdr.index_offset;
01349             }
01350             else {
01351                 subblocks.subs[i].read_size = 0;
01352                 subblocks.subs[i].i_offset  = 0;
01353             }
01354         }
01355         free(buf);
01356         memcpy(&block_hdr, subblocks.subs[0].buf, sizeof(block_hdr));
01357         LE16_CPU(block_hdr.index_offset);
01358         LE16_CPU(block_hdr.type);
01359         LE32_CPU(block_hdr.offset);
01360         DEBUG_EMAIL(("block header (index_offset=%#hx, type=%#hx, offset=%#hx)\n", block_hdr.index_offset, block_hdr.type, block_hdr.offset));
01361     }
01362     else {
01363         // setup the subblock descriptors, but we only have one block
01364         subblocks.subblock_count = (size_t)1;
01365         subblocks.subs = malloc(sizeof(pst_subblock));
01366         subblocks.subs[0].buf       = buf;
01367         subblocks.subs[0].read_size = read_size;
01368         subblocks.subs[0].i_offset  = block_hdr.index_offset;
01369     }
01370 
01371     if (block_hdr.type == (uint16_t)0xBCEC) { //type 1
01372         block_type = 1;
01373 
01374         if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, block_hdr.offset, &block_offset1)) {
01375             DEBUG_WARN(("internal error (bc.b5 offset %#x) in reading block id %#"PRIx64"\n", block_hdr.offset, block_id));
01376             freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01377             DEBUG_RET();
01378             return NULL;
01379         }
01380         memcpy(&table_rec, block_offset1.from, sizeof(table_rec));
01381         LE16_CPU(table_rec.type);
01382         LE16_CPU(table_rec.ref_type);
01383         LE32_CPU(table_rec.value);
01384         DEBUG_EMAIL(("table_rec (type=%#hx, ref_type=%#hx, value=%#x)\n", table_rec.type, table_rec.ref_type, table_rec.value));
01385 
01386         if ((table_rec.type != (uint16_t)0x02B5) || (table_rec.ref_type != 6)) {
01387             WARN(("Unknown second block constant - %#hx %#hx for id %#"PRIx64"\n", table_rec.type, table_rec.ref_type, block_id));
01388             freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01389             DEBUG_RET();
01390             return NULL;
01391         }
01392 
01393         if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, table_rec.value, &block_offset2)) {
01394             DEBUG_WARN(("internal error (bc.b5.desc offset #x) in reading block id %#"PRIx64"\n", table_rec.value, block_id));
01395             freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01396             DEBUG_RET();
01397             return NULL;
01398         }
01399         list_start = block_offset2.from;
01400         to_ptr     = block_offset2.to;
01401         num_list = (to_ptr - list_start)/sizeof(table_rec);
01402         num_recs = 1; // only going to be one object in these blocks
01403     }
01404     else if (block_hdr.type == (uint16_t)0x7CEC) { //type 2
01405         block_type = 2;
01406 
01407         if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, block_hdr.offset, &block_offset3)) {
01408             DEBUG_WARN(("internal error (7c.7c offset %#x) in reading block id %#"PRIx64"\n", block_hdr.offset, block_id));
01409             freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01410             DEBUG_RET();
01411             return NULL;
01412         }
01413         fr_ptr = block_offset3.from; //now got pointer to "7C block"
01414         memset(&seven_c_blk, 0, sizeof(seven_c_blk));
01415         memcpy(&seven_c_blk, fr_ptr, sizeof(seven_c_blk));
01416         LE16_CPU(seven_c_blk.u1);
01417         LE16_CPU(seven_c_blk.u2);
01418         LE16_CPU(seven_c_blk.u3);
01419         LE16_CPU(seven_c_blk.rec_size);
01420         LE32_CPU(seven_c_blk.b_five_offset);
01421         LE32_CPU(seven_c_blk.ind2_offset);
01422         LE16_CPU(seven_c_blk.u7);
01423         LE16_CPU(seven_c_blk.u8);
01424 
01425         list_start = fr_ptr + sizeof(seven_c_blk); // the list of item numbers start after this record
01426 
01427         if (seven_c_blk.seven_c != 0x7C) { // this would mean it isn't a 7C block!
01428             WARN(("Error. There isn't a 7C where I want to see 7C!\n"));
01429             freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01430             DEBUG_RET();
01431             return NULL;
01432         }
01433 
01434         rec_size = seven_c_blk.rec_size;
01435         num_list = (int32_t)(unsigned)seven_c_blk.item_count;
01436 
01437         if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, seven_c_blk.b_five_offset, &block_offset4)) {
01438             DEBUG_WARN(("internal error (7c.b5 offset %#x) in reading block id %#"PRIx64"\n", seven_c_blk.b_five_offset, block_id));
01439             freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01440             DEBUG_RET();
01441             return NULL;
01442         }
01443         memcpy(&table_rec, block_offset4.from, sizeof(table_rec));
01444         LE16_CPU(table_rec.type);
01445         LE16_CPU(table_rec.ref_type);
01446         LE32_CPU(table_rec.value);
01447         DEBUG_EMAIL(("table_rec (type=%#hx, ref_type=%#hx, value=%#x)\n", table_rec.type, table_rec.ref_type, table_rec.value));
01448 
01449         if (table_rec.type != (uint16_t)0x04B5) { // different constant than a type 1 record
01450             WARN(("Unknown second block constant - %#hx for id %#"PRIx64"\n", table_rec.type, block_id));
01451             freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01452             DEBUG_RET();
01453             return NULL;
01454         }
01455 
01456         if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, table_rec.value, &block_offset5)) {
01457             DEBUG_WARN(("internal error (7c.b5.desc offset %#x) in reading block id %#"PRIx64"\n", table_rec.value, block_id));
01458             freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01459             DEBUG_RET();
01460             return NULL;
01461         }
01462 
01463         // this will give the number of records in this block
01464         num_recs = (block_offset5.to - block_offset5.from) / (4 + table_rec.ref_type);
01465 
01466         if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, seven_c_blk.ind2_offset, &block_offset6)) {
01467             DEBUG_WARN(("internal error (7c.ind2 offset %#x) in reading block id %#"PRIx64"\n", seven_c_blk.ind2_offset, block_id));
01468             freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01469             DEBUG_RET();
01470             return NULL;
01471         }
01472         ind2_ptr = block_offset6.from;
01473         ind2_end = block_offset6.to;
01474     }
01475     else {
01476         WARN(("ERROR: Unknown block constant - %#hx for id %#"PRIx64"\n", block_hdr.type, block_id));
01477         freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01478         DEBUG_RET();
01479         return NULL;
01480     }
01481 
01482     DEBUG_EMAIL(("Mallocing number of records %i\n", num_recs));
01483     for (count_rec=0; count_rec<num_recs; count_rec++) {
01484         mo_ptr = (pst_mapi_object*) xmalloc(sizeof(pst_mapi_object));
01485         memset(mo_ptr, 0, sizeof(pst_mapi_object));
01486         mo_ptr->next = mo_head;
01487         mo_head = mo_ptr;
01488         // allocate an array of count num_recs to contain sizeof(pst_mapi_element)
01489         mo_ptr->elements        = (pst_mapi_element**) xmalloc(sizeof(pst_mapi_element)*num_list);
01490         mo_ptr->count_elements  = num_list;
01491         mo_ptr->orig_count      = num_list;
01492         mo_ptr->count_objects   = (int32_t)num_recs; // each record will have a record of the total number of records
01493         for (x=0; x<num_list; x++) mo_ptr->elements[x] = NULL;
01494         x = 0;
01495 
01496         DEBUG_EMAIL(("going to read %i (%#x) items\n", mo_ptr->count_elements, mo_ptr->count_elements));
01497 
01498         fr_ptr = list_start; // initialize fr_ptr to the start of the list.
01499         for (cur_list=0; cur_list<num_list; cur_list++) { //we will increase fr_ptr as we progress through index
01500             char* value_pointer = NULL;     // needed for block type 2 with values larger than 4 bytes
01501             size_t value_size = 0;
01502             if (block_type == 1) {
01503                 memcpy(&table_rec, fr_ptr, sizeof(table_rec));
01504                 LE16_CPU(table_rec.type);
01505                 LE16_CPU(table_rec.ref_type);
01506                 //LE32_CPU(table_rec.value);    // done later, some may be order invariant
01507                 fr_ptr += sizeof(table_rec);
01508             } else if (block_type == 2) {
01509                 // we will copy the table2_rec values into a table_rec record so that we can keep the rest of the code
01510                 memcpy(&table2_rec, fr_ptr, sizeof(table2_rec));
01511                 LE16_CPU(table2_rec.ref_type);
01512                 LE16_CPU(table2_rec.type);
01513                 LE16_CPU(table2_rec.ind2_off);
01514 
01515                 // table_rec and table2_rec are arranged differently, so assign the values across
01516                 table_rec.type     = table2_rec.type;
01517                 table_rec.ref_type = table2_rec.ref_type;
01518                 table_rec.value    = 0;
01519                 if ((ind2_end - ind2_ptr) >= (int)(table2_rec.ind2_off + table2_rec.size)) {
01520                     size_t n = table2_rec.size;
01521                     size_t m = sizeof(table_rec.value);
01522                     if (n <= m) {
01523                         memcpy(&table_rec.value, ind2_ptr + table2_rec.ind2_off, n);
01524                     }
01525                     else {
01526                         value_pointer = ind2_ptr + table2_rec.ind2_off;
01527                         value_size    = n;
01528                     }
01529                     //LE32_CPU(table_rec.value);    // done later, some may be order invariant
01530                 }
01531                 else {
01532                     DEBUG_WARN (("Trying to read outside buffer, buffer size %#x, offset %#x, data size %#x\n",
01533                                 read_size, ind2_end-ind2_ptr+table2_rec.ind2_off, table2_rec.size));
01534                 }
01535                 fr_ptr += sizeof(table2_rec);
01536             } else {
01537                 WARN(("Missing code for block_type %i\n", block_type));
01538                 freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01539                 pst_free_list(mo_head);
01540                 DEBUG_RET();
01541                 return NULL;
01542             }
01543             DEBUG_EMAIL(("reading block %i (type=%#x, ref_type=%#x, value=%#x)\n",
01544                 x, table_rec.type, table_rec.ref_type, table_rec.value));
01545 
01546             if (!mo_ptr->elements[x]) {
01547                 mo_ptr->elements[x] = (pst_mapi_element*) xmalloc(sizeof(pst_mapi_element));
01548             }
01549             memset(mo_ptr->elements[x], 0, sizeof(pst_mapi_element)); //init it
01550 
01551             // check here to see if the id of the attribute is a mapped one
01552             mapptr = pf->x_head;
01553             while (mapptr && (mapptr->map < table_rec.type)) mapptr = mapptr->next;
01554             if (mapptr && (mapptr->map == table_rec.type)) {
01555                 if (mapptr->mytype == PST_MAP_ATTRIB) {
01556                     mo_ptr->elements[x]->mapi_id = *((uint32_t*)mapptr->data);
01557                     DEBUG_EMAIL(("Mapped attrib %#x to %#x\n", table_rec.type, mo_ptr->elements[x]->mapi_id));
01558                 } else if (mapptr->mytype == PST_MAP_HEADER) {
01559                     DEBUG_EMAIL(("Internet Header mapping found %#x\n", table_rec.type));
01560                     mo_ptr->elements[x]->mapi_id = (uint32_t)PST_ATTRIB_HEADER;
01561                     mo_ptr->elements[x]->extra = mapptr->data;
01562                 }
01563                 else {
01564                     DEBUG_WARN(("Missing assertion failure\n"));
01565                     // nothing, should be assertion failure here
01566                 }
01567             } else {
01568                 mo_ptr->elements[x]->mapi_id = table_rec.type;
01569             }
01570             mo_ptr->elements[x]->type = 0; // checked later before it is set
01571             /* Reference Types
01572                 0x0002 - Signed 16bit value
01573                 0x0003 - Signed 32bit value
01574                 0x0004 - 4-byte floating point
01575                 0x0005 - Floating point double
01576                 0x0006 - Signed 64-bit int
01577                 0x0007 - Application Time
01578                 0x000A - 32-bit error value
01579                 0x000B - Boolean (non-zero = true)
01580                 0x000D - Embedded Object
01581                 0x0014 - 8-byte signed integer (64-bit)
01582                 0x001E - Null terminated String
01583                 0x001F - Unicode string
01584                 0x0040 - Systime - Filetime structure
01585                 0x0048 - OLE Guid
01586                 0x0102 - Binary data
01587                 0x1003 - Array of 32bit values
01588                 0x1014 - Array of 64bit values
01589                 0x101E - Array of Strings
01590                 0x1102 - Array of Binary data
01591             */
01592 
01593             if (table_rec.ref_type == (uint16_t)0x0002 ||
01594                 table_rec.ref_type == (uint16_t)0x0003 ||
01595                 table_rec.ref_type == (uint16_t)0x000b) {
01596                 //contains 32 bits of data
01597                 mo_ptr->elements[x]->size = sizeof(int32_t);
01598                 mo_ptr->elements[x]->type = table_rec.ref_type;
01599                 mo_ptr->elements[x]->data = xmalloc(sizeof(int32_t));
01600                 memcpy(mo_ptr->elements[x]->data, &(table_rec.value), sizeof(int32_t));
01601                 // are we missing an LE32_CPU() call here? table_rec.value is still
01602                 // in the original order.
01603 
01604             } else if (table_rec.ref_type == (uint16_t)0x0005 ||
01605                        table_rec.ref_type == (uint16_t)0x000d ||
01606                        table_rec.ref_type == (uint16_t)0x0014 ||
01607                        table_rec.ref_type == (uint16_t)0x001e ||
01608                        table_rec.ref_type == (uint16_t)0x001f ||
01609                        table_rec.ref_type == (uint16_t)0x0040 ||
01610                        table_rec.ref_type == (uint16_t)0x0048 ||
01611                        table_rec.ref_type == (uint16_t)0x0102 ||
01612                        table_rec.ref_type == (uint16_t)0x1003 ||
01613                        table_rec.ref_type == (uint16_t)0x1014 ||
01614                        table_rec.ref_type == (uint16_t)0x101e ||
01615                        table_rec.ref_type == (uint16_t)0x101f ||
01616                        table_rec.ref_type == (uint16_t)0x1102) {
01617                 //contains index reference to data
01618                 LE32_CPU(table_rec.value);
01619                 if (value_pointer) {
01620                     // in a type 2 block, with a value that is more than 4 bytes
01621                     // directly stored in this block.
01622                     mo_ptr->elements[x]->size = value_size;
01623                     mo_ptr->elements[x]->type = table_rec.ref_type;
01624                     mo_ptr->elements[x]->data = xmalloc(value_size);
01625                     memcpy(mo_ptr->elements[x]->data, value_pointer, value_size);
01626                 }
01627                 else if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, table_rec.value, &block_offset7)) {
01628                     if ((table_rec.value & 0xf) == (uint32_t)0xf) {
01629                         DEBUG_WARN(("failed to get block offset for table_rec.value of %#x to be read later.\n", table_rec.value));
01630                         mo_ptr->elements[x]->size = 0;
01631                         mo_ptr->elements[x]->data = NULL;
01632                         mo_ptr->elements[x]->type = table_rec.value;
01633                     }
01634                     else {
01635                         if (table_rec.value) {
01636                             DEBUG_WARN(("failed to get block offset for table_rec.value of %#x\n", table_rec.value));
01637                         }
01638                         mo_ptr->count_elements --; //we will be skipping a row
01639                         continue;
01640                     }
01641                 }
01642                 else {
01643                     value_size = (size_t)(block_offset7.to - block_offset7.from);
01644                     mo_ptr->elements[x]->size = value_size;
01645                     mo_ptr->elements[x]->type = table_rec.ref_type;
01646                     mo_ptr->elements[x]->data = xmalloc(value_size+1);
01647                     memcpy(mo_ptr->elements[x]->data, block_offset7.from, value_size);
01648                     mo_ptr->elements[x]->data[value_size] = '\0';  // it might be a string, null terminate it.
01649                 }
01650                 if (table_rec.ref_type == (uint16_t)0xd) {
01651                     // there is still more to do for the type of 0xD embedded objects
01652                     type_d_rec = (struct _type_d_rec*) mo_ptr->elements[x]->data;
01653                     LE32_CPU(type_d_rec->id);
01654                     mo_ptr->elements[x]->size = pst_ff_getID2block(pf, type_d_rec->id, i2_head, &(mo_ptr->elements[x]->data));
01655                     if (!mo_ptr->elements[x]->size){
01656                         DEBUG_WARN(("not able to read the ID2 data. Setting to be read later. %#x\n", type_d_rec->id));
01657                         mo_ptr->elements[x]->type = type_d_rec->id;    // fetch before freeing data, alias pointer
01658                         free(mo_ptr->elements[x]->data);
01659                         mo_ptr->elements[x]->data = NULL;
01660                     }
01661                 }
01662                 if (table_rec.ref_type == (uint16_t)0x1f) {
01663                     // there is more to do for the type 0x1f unicode strings
01664                     size_t rc;
01665                     static vbuf *utf16buf = NULL;
01666                     static vbuf *utf8buf  = NULL;
01667                     if (!utf16buf) utf16buf = vballoc((size_t)1024);
01668                     if (!utf8buf)  utf8buf  = vballoc((size_t)1024);
01669 
01670                     // splint barfed on the following lines
01671                     //VBUF_STATIC(utf16buf, 1024);
01672                     //VBUF_STATIC(utf8buf, 1024);
01673 
01674                     //need UTF-16 zero-termination
01675                     vbset(utf16buf, mo_ptr->elements[x]->data, mo_ptr->elements[x]->size);
01676                     vbappend(utf16buf, "\0\0", (size_t)2);
01677                     DEBUG_INDEX(("Iconv in:\n"));
01678                     DEBUG_HEXDUMPC(utf16buf->b, utf16buf->dlen, 0x10);
01679                     rc = vb_utf16to8(utf8buf, utf16buf->b, utf16buf->dlen);
01680                     if (rc == (size_t)-1) {
01681                         DEBUG_EMAIL(("Failed to convert utf-16 to utf-8\n"));
01682                     }
01683                     else {
01684                         free(mo_ptr->elements[x]->data);
01685                         mo_ptr->elements[x]->size = utf8buf->dlen;
01686                         mo_ptr->elements[x]->data = xmalloc(utf8buf->dlen);
01687                         memcpy(mo_ptr->elements[x]->data, utf8buf->b, utf8buf->dlen);
01688                     }
01689                     DEBUG_INDEX(("Iconv out:\n"));
01690                     DEBUG_HEXDUMPC(mo_ptr->elements[x]->data, mo_ptr->elements[x]->size, 0x10);
01691                 }
01692                 if (mo_ptr->elements[x]->type == 0) mo_ptr->elements[x]->type = table_rec.ref_type;
01693             } else {
01694                 WARN(("ERROR Unknown ref_type %#hx\n", table_rec.ref_type));
01695                 freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01696                 pst_free_list(mo_head);
01697                 DEBUG_RET();
01698                 return NULL;
01699             }
01700             x++;
01701         }
01702         DEBUG_EMAIL(("increasing ind2_ptr by %i [%#x] bytes. Was %#x, Now %#x\n", rec_size, rec_size, ind2_ptr, ind2_ptr+rec_size));
01703         ind2_ptr += rec_size;
01704     }
01705     freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01706     DEBUG_RET();
01707     return mo_head;
01708 }
01709 
01710 
01711 // This version of free does NULL check first
01712 #define SAFE_FREE(x) {if (x) free(x);}
01713 #define SAFE_FREE_STR(x) SAFE_FREE(x.str)
01714 #define SAFE_FREE_BIN(x) SAFE_FREE(x.data)
01715 
01716 // check if item->email is NULL, and init if so
01717 #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)        );} }
01718 #define MALLOC_FOLDER(x)       { if (!x->folder)        { x->folder        = (pst_item_folder*)        xmalloc(sizeof(pst_item_folder));        memset(x->folder,        0, sizeof(pst_item_folder)       );} }
01719 #define MALLOC_CONTACT(x)      { if (!x->contact)       { x->contact       = (pst_item_contact*)       xmalloc(sizeof(pst_item_contact));       memset(x->contact,       0, sizeof(pst_item_contact)      );} }
01720 #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));} }
01721 #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)      );} }
01722 #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)  );} }
01723 
01724 // malloc space and copy the current item's data null terminated
01725 #define LIST_COPY(targ, type) {                                    \
01726     targ = type realloc(targ, list->elements[x]->size+1);          \
01727     memcpy(targ, list->elements[x]->data, list->elements[x]->size);\
01728     memset(((char*)targ)+list->elements[x]->size, 0, (size_t)1);   \
01729 }
01730 
01731 #define LIST_COPY_CSTR(targ) {                                              \
01732     if ((list->elements[x]->type == 0x1f) ||                                \
01733         (list->elements[x]->type == 0x1e) ||                                \
01734         (list->elements[x]->type == 0x102)) {                               \
01735         LIST_COPY(targ, (char*))                                            \
01736     }                                                                       \
01737     else {                                                                  \
01738         DEBUG_EMAIL(("src not 0x1e or 0x1f or 0x102 for string dst\n"));    \
01739         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);    \
01740         SAFE_FREE(targ);                                                    \
01741         targ = NULL;                                                        \
01742     }                                                                       \
01743 }
01744 
01745 #define LIST_COPY_BOOL(label, targ) {                                       \
01746     if (list->elements[x]->type != 0x0b) {                                  \
01747         DEBUG_EMAIL(("src not 0x0b for boolean dst\n"));                    \
01748         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);    \
01749     }                                                                       \
01750     if (*(int16_t*)list->elements[x]->data) {                               \
01751         DEBUG_EMAIL((label" - True\n"));                                    \
01752         targ = 1;                                                           \
01753     } else {                                                                \
01754         DEBUG_EMAIL((label" - False\n"));                                   \
01755         targ = 0;                                                           \
01756     }                                                                       \
01757 }
01758 
01759 #define LIST_COPY_EMAIL_BOOL(label, targ) {                     \
01760     MALLOC_EMAIL(item);                                         \
01761     LIST_COPY_BOOL(label, targ)                                 \
01762 }
01763 
01764 #define LIST_COPY_CONTACT_BOOL(label, targ) {                   \
01765     MALLOC_CONTACT(item);                                       \
01766     LIST_COPY_BOOL(label, targ)                                 \
01767 }
01768 
01769 #define LIST_COPY_APPT_BOOL(label, targ) {                      \
01770     MALLOC_APPOINTMENT(item);                                   \
01771     LIST_COPY_BOOL(label, targ)                                 \
01772 }
01773 
01774 #define LIST_COPY_INT16_N(targ) {                                           \
01775     if (list->elements[x]->type != 0x02) {                                  \
01776         DEBUG_EMAIL(("src not 0x02 for int16 dst\n"));                      \
01777         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);    \
01778     }                                                                       \
01779     memcpy(&(targ), list->elements[x]->data, sizeof(targ));                 \
01780     LE16_CPU(targ);                                                         \
01781 }
01782 
01783 #define LIST_COPY_INT16(label, targ) {                          \
01784     LIST_COPY_INT16_N(targ);                                    \
01785     DEBUG_EMAIL((label" - %i %#x\n", (int)targ, (int)targ));    \
01786 }
01787 
01788 #define LIST_COPY_INT32_N(targ) {                                           \
01789     if (list->elements[x]->type != 0x03) {                                  \
01790         DEBUG_EMAIL(("src not 0x03 for int32 dst\n"));                      \
01791         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);    \
01792     }                                                                       \
01793     memcpy(&(targ), list->elements[x]->data, sizeof(targ));                 \
01794     LE32_CPU(targ);                                                         \
01795 }
01796 
01797 #define LIST_COPY_INT32(label, targ) {                          \
01798     LIST_COPY_INT32_N(targ);                                    \
01799     DEBUG_EMAIL((label" - %i %#x\n", (int)targ, (int)targ));    \
01800 }
01801 
01802 #define LIST_COPY_EMAIL_INT32(label, targ) {                    \
01803     MALLOC_EMAIL(item);                                         \
01804     LIST_COPY_INT32(label, targ);                               \
01805 }
01806 
01807 #define LIST_COPY_APPT_INT32(label, targ) {                     \
01808     MALLOC_APPOINTMENT(item);                                   \
01809     LIST_COPY_INT32(label, targ);                               \
01810 }
01811 
01812 #define LIST_COPY_FOLDER_INT32(label, targ) {                   \
01813     MALLOC_FOLDER(item);                                        \
01814     LIST_COPY_INT32(label, targ);                               \
01815 }
01816 
01817 #define LIST_COPY_STORE_INT32(label, targ) {                    \
01818     MALLOC_MESSAGESTORE(item);                                  \
01819     LIST_COPY_INT32(label, targ);                               \
01820 }
01821 
01822 #define LIST_COPY_ENUM(label, targ, delta, count, ...) {        \
01823     char *tlabels[] = {__VA_ARGS__};                            \
01824     LIST_COPY_INT32_N(targ);                                    \
01825     targ += delta;                                              \
01826     DEBUG_EMAIL((label" - %s [%i]\n",                           \
01827         (((int)targ < 0) || ((int)targ >= count))               \
01828             ? "**invalid"                                       \
01829             : tlabels[(int)targ], (int)targ));                  \
01830 }
01831 
01832 #define LIST_COPY_EMAIL_ENUM(label, targ, delta, count, ...) {  \
01833     MALLOC_EMAIL(item);                                         \
01834     LIST_COPY_ENUM(label, targ, delta, count, __VA_ARGS__);     \
01835 }
01836 
01837 #define LIST_COPY_APPT_ENUM(label, targ, delta, count, ...) {   \
01838     MALLOC_APPOINTMENT(item);                                   \
01839     LIST_COPY_ENUM(label, targ, delta, count, __VA_ARGS__);     \
01840 }
01841 
01842 #define LIST_COPY_ENUM16(label, targ, delta, count, ...) {      \
01843     char *tlabels[] = {__VA_ARGS__};                            \
01844     LIST_COPY_INT16_N(targ);                                    \
01845     targ += delta;                                              \
01846     DEBUG_EMAIL((label" - %s [%i]\n",                           \
01847         (((int)targ < 0) || ((int)targ >= count))               \
01848             ? "**invalid"                                       \
01849             : tlabels[(int)targ], (int)targ));                  \
01850 }
01851 
01852 #define LIST_COPY_CONTACT_ENUM16(label, targ, delta, count, ...) {  \
01853     MALLOC_CONTACT(item);                                           \
01854     LIST_COPY_ENUM16(label, targ, delta, count, __VA_ARGS__);       \
01855 }
01856 
01857 #define LIST_COPY_ENTRYID(label, targ) {                        \
01858     LIST_COPY(targ, (pst_entryid*));                            \
01859     LE32_CPU(targ->u1);                                         \
01860     LE32_CPU(targ->id);                                         \
01861     DEBUG_EMAIL((label" u1=%#x, id=%#x\n", targ->u1, targ->id));\
01862 }
01863 
01864 #define LIST_COPY_EMAIL_ENTRYID(label, targ) {                  \
01865     MALLOC_EMAIL(item);                                         \
01866     LIST_COPY_ENTRYID(label, targ);                             \
01867 }
01868 
01869 #define LIST_COPY_STORE_ENTRYID(label, targ) {                  \
01870     MALLOC_MESSAGESTORE(item);                                  \
01871     LIST_COPY_ENTRYID(label, targ);                             \
01872 }
01873 
01874 
01875 // malloc space and copy the current item's data null terminated
01876 // including the utf8 flag
01877 #define LIST_COPY_STR(label, targ) {                                    \
01878     LIST_COPY_CSTR(targ.str);                                           \
01879     targ.is_utf8 = (list->elements[x]->type == 0x1f) ? 1 : 0;           \
01880     DEBUG_EMAIL((label" - unicode %d - %s\n", targ.is_utf8, targ.str)); \
01881 }
01882 
01883 #define LIST_COPY_EMAIL_STR(label, targ) {                      \
01884     MALLOC_EMAIL(item);                                         \
01885     LIST_COPY_STR(label, targ);                                 \
01886 }
01887 
01888 #define LIST_COPY_CONTACT_STR(label, targ) {                    \
01889     MALLOC_CONTACT(item);                                       \
01890     LIST_COPY_STR(label, targ);                                 \
01891 }
01892 
01893 #define LIST_COPY_APPT_STR(label, targ) {                       \
01894     MALLOC_APPOINTMENT(item);                                   \
01895     LIST_COPY_STR(label, targ);                                 \
01896 }
01897 
01898 #define LIST_COPY_JOURNAL_STR(label, targ) {                    \
01899     MALLOC_JOURNAL(item);                                       \
01900     LIST_COPY_STR(label, targ);                                 \
01901 }
01902 
01903 // malloc space and copy the item filetime
01904 #define LIST_COPY_TIME(label, targ) {                                       \
01905     if (list->elements[x]->type != 0x40) {                                  \
01906         DEBUG_EMAIL(("src not 0x40 for filetime dst\n"));                   \
01907         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);    \
01908     }                                                                       \
01909     targ = (FILETIME*) realloc(targ, sizeof(FILETIME));                     \
01910     memcpy(targ, list->elements[x]->data, list->elements[x]->size);         \
01911     LE32_CPU(targ->dwLowDateTime);                                          \
01912     LE32_CPU(targ->dwHighDateTime);                                         \
01913     DEBUG_EMAIL((label" - %s", fileTimeToAscii(targ)));                     \
01914 }
01915 
01916 #define LIST_COPY_EMAIL_TIME(label, targ) {                     \
01917     MALLOC_EMAIL(item);                                         \
01918     LIST_COPY_TIME(label, targ);                                \
01919 }
01920 
01921 #define LIST_COPY_CONTACT_TIME(label, targ) {                   \
01922     MALLOC_CONTACT(item);                                       \
01923     LIST_COPY_TIME(label, targ);                                \
01924 }
01925 
01926 #define LIST_COPY_APPT_TIME(label, targ) {                      \
01927     MALLOC_APPOINTMENT(item);                                   \
01928     LIST_COPY_TIME(label, targ);                                \
01929 }
01930 
01931 #define LIST_COPY_JOURNAL_TIME(label, targ) {                   \
01932     MALLOC_JOURNAL(item);                                       \
01933     LIST_COPY_TIME(label, targ);                                \
01934 }
01935 
01936 // malloc space and copy the current item's data and size
01937 #define LIST_COPY_BIN(targ) {                                       \
01938     targ.size = list->elements[x]->size;                            \
01939     if (targ.size) {                                                \
01940         targ.data = (char*)realloc(targ.data, targ.size);           \
01941         memcpy(targ.data, list->elements[x]->data, targ.size);      \
01942     }                                                               \
01943     else {                                                          \
01944         SAFE_FREE_BIN(targ);                                        \
01945         targ.data = NULL;                                           \
01946     }                                                               \
01947 }
01948 
01949 #define LIST_COPY_EMAIL_BIN(label, targ) {          \
01950     MALLOC_EMAIL(item);                             \
01951     LIST_COPY_BIN(targ);                            \
01952     DEBUG_EMAIL((label"\n"));                       \
01953 }
01954 
01955 #define NULL_CHECK(x) { if (!x) { DEBUG_EMAIL(("NULL_CHECK: Null Found\n")); break;} }
01956 
01957 
01972 int pst_process(pst_mapi_object *list, pst_item *item, pst_item_attach *attach) {
01973     DEBUG_ENT("pst_process");
01974     if (!item) {
01975         DEBUG_EMAIL(("item cannot be NULL.\n"));
01976         DEBUG_RET();
01977         return -1;
01978     }
01979 
01980     while (list) {
01981         int32_t x;
01982         for (x=0; x<list->count_elements; x++) {
01983             int32_t t;
01984             pst_item_extra_field *ef;
01985             // check here to see if the id is one that is mapped.
01986             DEBUG_EMAIL(("#%d - mapi-id: %#x type: %#x length: %#x\n", x, list->elements[x]->mapi_id, list->elements[x]->type, list->elements[x]->size));
01987 
01988             switch (list->elements[x]->mapi_id) {
01989                 case PST_ATTRIB_HEADER: // CUSTOM attribute for saying the Extra Headers
01990                     if ((list->elements[x]->extra) &&
01991                         ((list->elements[x]->type == 0x1f)  ||
01992                          (list->elements[x]->type == 0x1e))) {
01993                         ef = (pst_item_extra_field*) xmalloc(sizeof(pst_item_extra_field));
01994                         memset(ef, 0, sizeof(pst_item_extra_field));
01995                         ef->field_name = (char*) xmalloc(strlen(list->elements[x]->extra)+1);
01996                         strcpy(ef->field_name, list->elements[x]->extra);
01997                         LIST_COPY_CSTR(ef->value);
01998                         ef->next = item->extra_fields;
01999                         item->extra_fields = ef;
02000                         DEBUG_EMAIL(("Extra Field - \"%s\" = \"%s\"\n", ef->field_name, ef->value));
02001                         if (strcmp(ef->field_name, "content-type") == 0) {
02002                             char *p = strstr(ef->value, "charset=\"");
02003                             if (p) {
02004                                 p += 9; // skip over charset="
02005                                 char *pp = strchr(p, '"');
02006                                 if (pp) {
02007                                     *pp = '\0';
02008                                     char *set = strdup(p);
02009                                     *pp = '"';
02010                                     if (item->body_charset.str) free(item->body_charset.str);
02011                                     item->body_charset.str     = set;
02012                                     item->body_charset.is_utf8 = 1;
02013                                     DEBUG_EMAIL(("body charset %s from content-type extra field\n", set));
02014                                 }
02015                             }
02016                         }
02017                     }
02018                     else {
02019                         DEBUG_EMAIL(("What does this mean?\n"));
02020                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02021                     }
02022                     break;
02023                 case 0x0002: // PR_ALTERNATE_RECIPIENT_ALLOWED
02024                     if (list->elements[x]->type == 0x0b) {
02025                         // If set to true, the sender allows this email to be autoforwarded
02026                         LIST_COPY_EMAIL_BOOL("AutoForward allowed", item->email->autoforward);
02027                         if (!item->email->autoforward) item->email->autoforward = -1;
02028                     } else {
02029                         DEBUG_EMAIL(("What does this mean?\n"));
02030                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02031                     }
02032                     break;
02033                 case 0x0003: // Extended Attributes table
02034                     DEBUG_EMAIL(("Extended Attributes Table - NOT PROCESSED\n"));
02035                     break;
02036                 case 0x0017: // PR_IMPORTANCE - How important the sender deems it to be
02037                     LIST_COPY_EMAIL_ENUM("Importance Level", item->email->importance, 0, 3, "Low", "Normal", "High");
02038                     break;
02039                 case 0x001A: // PR_MESSAGE_CLASS IPM.x
02040                     if ((list->elements[x]->type == 0x1e) ||
02041                         (list->elements[x]->type == 0x1f)) {
02042                         LIST_COPY_CSTR(item->ascii_type);
02043                         if (!item->ascii_type) item->ascii_type = strdup("unknown");
02044                         if (pst_strincmp("IPM.Note", item->ascii_type, 8) == 0)
02045                             item->type = PST_TYPE_NOTE;
02046                         else if (pst_stricmp("IPM", item->ascii_type) == 0)
02047                             item->type = PST_TYPE_NOTE;
02048                         else if (pst_strincmp("IPM.Contact", item->ascii_type, 11) == 0)
02049                             item->type = PST_TYPE_CONTACT;
02050                         else if (pst_strincmp("REPORT.IPM.Note", item->ascii_type, 15) == 0)
02051                             item->type = PST_TYPE_REPORT;
02052                         else if (pst_strincmp("IPM.Activity", item->ascii_type, 12) == 0)
02053                             item->type = PST_TYPE_JOURNAL;
02054                         else if (pst_strincmp("IPM.Appointment", item->ascii_type, 15) == 0)
02055                             item->type = PST_TYPE_APPOINTMENT;
02056                         //else if (pst_strincmp("IPM.Schedule.Meeting", item->ascii_type, 20) == 0)
02057                         //    item->type = PST_TYPE_APPOINTMENT;
02058                         // these seem to be appointments, but they are inside the email folder,
02059                         // and unless we are in separate mode, we would dump an appointment
02060                         // into the middle of a mailbox file.
02061                         else if (pst_strincmp("IPM.StickyNote", item->ascii_type, 14) == 0)
02062                             item->type = PST_TYPE_STICKYNOTE;
02063                         else if (pst_strincmp("IPM.Task", item->ascii_type, 8) == 0)
02064                             item->type = PST_TYPE_TASK;
02065                         else
02066                             item->type = PST_TYPE_OTHER;
02067                         DEBUG_EMAIL(("Message class %s [%"PRIi32"] \n", item->ascii_type, item->type));
02068                     }
02069                     else {
02070                         DEBUG_EMAIL(("What does this mean?\n"));
02071                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02072                     }
02073                     break;
02074                 case 0x0023: // PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED
02075                     if (list->elements[x]->type == 0x0b) {
02076                         // set if the sender wants a delivery report from all recipients
02077                         LIST_COPY_EMAIL_BOOL("Global Delivery Report", item->email->delivery_report);
02078                     }
02079                     else {
02080                         DEBUG_EMAIL(("What does this mean?\n"));
02081                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02082                     }
02083                     break;
02084                 case 0x0026: // PR_PRIORITY
02085                     LIST_COPY_EMAIL_ENUM("Priority", item->email->priority, 1, 3, "NonUrgent", "Normal", "Urgent");
02086                     break;
02087                 case 0x0029: // PR_READ_RECEIPT_REQUESTED
02088                     LIST_COPY_EMAIL_BOOL("Read Receipt", item->email->read_receipt);
02089                     break;
02090                 case 0x002B: // PR_RECIPIENT_REASSIGNMENT_PROHIBITED
02091                     LIST_COPY_BOOL("Reassignment Prohibited (Private)", item->private_member);
02092                     break;
02093                 case 0x002E: // PR_ORIGINAL_SENSITIVITY - the sensitivity of the message before being replied to or forwarded
02094                     LIST_COPY_EMAIL_ENUM("Original Sensitivity", item->email->original_sensitivity, 0, 4,
02095                         "None", "Personal", "Private", "Company Confidential");
02096                     break;
02097                 case 0x0032: // PR_REPORT_TIME
02098                     LIST_COPY_EMAIL_TIME("Report time", item->email->report_time);
02099                     break;
02100                 case 0x0036: // PR_SENSITIVITY - sender's opinion of the sensitivity of an email
02101                     LIST_COPY_EMAIL_ENUM("Sensitivity", item->email->sensitivity, 0, 4,
02102                         "None", "Personal", "Private", "Company Confidential");
02103                     break;
02104                 case 0x0037: // PR_SUBJECT raw subject
02105                     {
02106                         int off = 0;
02107                         if ((list->elements[x]->size > 2) && (((uint8_t)list->elements[x]->data[0]) < 0x20)) {
02108                             off = 2;
02109                         }
02110                         list->elements[x]->data += off;
02111                         list->elements[x]->size -= off;
02112                         LIST_COPY_STR("Raw Subject", item->subject);
02113                         list->elements[x]->size += off;
02114                         list->elements[x]->data -= off;
02115                     }
02116                     break;
02117                 case 0x0039: // PR_CLIENT_SUBMIT_TIME Date Email Sent/Created
02118                     LIST_COPY_EMAIL_TIME("Date sent", item->email->sent_date);
02119                     break;
02120                 case 0x003B: // PR_SENT_REPRESENTING_SEARCH_KEY Sender address 1
02121                     LIST_COPY_EMAIL_STR("Sent on behalf of address 1", item->email->outlook_sender);
02122                     break;
02123                 case 0x003F: // PR_RECEIVED_BY_ENTRYID Structure containing Recipient
02124                     DEBUG_EMAIL(("Recipient Structure 1 -- NOT HANDLED\n"));
02125                     break;
02126                 case 0x0040: // PR_RECEIVED_BY_NAME Name of Recipient Structure
02127                     DEBUG_EMAIL(("Received By Name 1 -- NOT HANDLED\n"));
02128                     break;
02129                 case 0x0041: // PR_SENT_REPRESENTING_ENTRYID Structure containing Sender
02130                     DEBUG_EMAIL(("Sent on behalf of Structure 1 -- NOT HANDLED\n"));
02131                     break;
02132                 case 0x0042: // PR_SENT_REPRESENTING_NAME
02133                     LIST_COPY_EMAIL_STR("Sent on behalf of", item->email->outlook_sender_name);
02134                     break;
02135                 case 0x0043: // PR_RCVD_REPRESENTING_ENTRYID Recipient Structure 2
02136                     DEBUG_EMAIL(("Received on behalf of Structure -- NOT HANDLED\n"));
02137                     break;
02138                 case 0x0044: // PR_RCVD_REPRESENTING_NAME
02139                     LIST_COPY_EMAIL_STR("Received on behalf of", item->email->outlook_recipient_name);
02140                     break;
02141                 case 0x004F: // PR_REPLY_RECIPIENT_ENTRIES Reply-To Structure
02142                     DEBUG_EMAIL(("Reply-To Structure -- NOT HANDLED\n"));
02143                     break;
02144                 case 0x0050: // PR_REPLY_RECIPIENT_NAMES Name of Reply-To Structure
02145                     LIST_COPY_EMAIL_STR("Reply-To", item->email->reply_to);
02146                     break;
02147                 case 0x0051: // PR_RECEIVED_BY_SEARCH_KEY Recipient Address 1
02148                     LIST_COPY_EMAIL_STR("Recipient's Address 1", item->email->outlook_recipient);
02149                     break;
02150                 case 0x0052: // PR_RCVD_REPRESENTING_SEARCH_KEY Recipient Address 2
02151                     LIST_COPY_EMAIL_STR("Recipient's Address 2", item->email->outlook_recipient2);
02152                     break;
02153                 case 0x0057: // PR_MESSAGE_TO_ME
02154                     // this user is listed explicitly in the TO address
02155                     LIST_COPY_EMAIL_BOOL("My address in TO field", item->email->message_to_me);
02156                     break;
02157                 case 0x0058: // PR_MESSAGE_CC_ME
02158                     // this user is listed explicitly in the CC address
02159                     LIST_COPY_EMAIL_BOOL("My address in CC field", item->email->message_cc_me);
02160                     break;
02161                 case 0x0059: // PR_MESSAGE_RECIP_ME
02162                     // this user appears in TO, CC or BCC address list
02163                     LIST_COPY_EMAIL_BOOL("Message addressed to me", item->email->message_recip_me);
02164                     break;
02165                 case 0x0063: // PR_RESPONSE_REQUESTED
02166                     LIST_COPY_BOOL("Response requested", item->response_requested);
02167                     break;
02168                 case 0x0064: // PR_SENT_REPRESENTING_ADDRTYPE Access method for Sender Address
02169                     LIST_COPY_EMAIL_STR("Sent on behalf of address type", item->email->sender_access);
02170                     break;
02171                 case 0x0065: // PR_SENT_REPRESENTING_EMAIL_ADDRESS Sender Address
02172                     LIST_COPY_EMAIL_STR("Sent on behalf of address", item->email->sender_address);
02173                     break;
02174                 case 0x0070: // PR_CONVERSATION_TOPIC Processed Subject
02175                     LIST_COPY_EMAIL_STR("Processed Subject (Conversation Topic)", item->email->processed_subject);
02176                     break;
02177                 case 0x0071: // PR_CONVERSATION_INDEX
02178                     LIST_COPY_EMAIL_BIN("Conversation Index", item->email->conversation_index);
02179                     break;
02180                 case 0x0072: // PR_ORIGINAL_DISPLAY_BCC
02181                     LIST_COPY_EMAIL_STR("Original display bcc", item->email->original_bcc);
02182                     break;
02183                 case 0x0073: // PR_ORIGINAL_DISPLAY_CC
02184                     LIST_COPY_EMAIL_STR("Original display cc", item->email->original_cc);
02185                     break;
02186                 case 0x0074: // PR_ORIGINAL_DISPLAY_TO
02187                     LIST_COPY_EMAIL_STR("Original display to", item->email->original_to);
02188                     break;
02189                 case 0x0075: // PR_RECEIVED_BY_ADDRTYPE Recipient Access Method
02190                     LIST_COPY_EMAIL_STR("Received by Address type", item->email->recip_access);
02191                     break;
02192                 case 0x0076: // PR_RECEIVED_BY_EMAIL_ADDRESS Recipient Address
02193                     LIST_COPY_EMAIL_STR("Received by Address", item->email->recip_address);
02194                     break;
02195                 case 0x0077: // PR_RCVD_REPRESENTING_ADDRTYPE Recipient Access Method 2
02196                     LIST_COPY_EMAIL_STR("Received on behalf of Address type", item->email->recip2_access);
02197                     break;
02198                 case 0x0078: // PR_RCVD_REPRESENTING_EMAIL_ADDRESS Recipient Address 2
02199                     LIST_COPY_EMAIL_STR("Received on behalf of Address", item->email->recip2_address);
02200                     break;
02201                 case 0x007D: // PR_TRANSPORT_MESSAGE_HEADERS Internet Header
02202                     LIST_COPY_EMAIL_STR("Internet Header", item->email->header);
02203                     break;
02204                 case 0x0C04: // PR_NDR_REASON_CODE
02205                     LIST_COPY_EMAIL_INT32("NDR reason code", item->email->ndr_reason_code);
02206                     break;
02207                 case 0x0C05: // PR_NDR_DIAG_CODE
02208                     LIST_COPY_EMAIL_INT32("NDR diag code", item->email->ndr_diag_code);
02209                     break;
02210                 case 0x0C06: // PR_NON_RECEIPT_NOTIFICATION_REQUESTED
02211                     DEBUG_EMAIL(("Non-Receipt Notification Requested - (ignored) - "));
02212                     break;
02213                 case 0x0C17: // PR_REPLY_REQUESTED
02214                     LIST_COPY_EMAIL_BOOL("Reply Requested", item->email->reply_requested);
02215                     break;
02216                 case 0x0C19: // PR_SENDER_ENTRYID Sender Structure 2
02217                     DEBUG_EMAIL(("Sender Structure 2 -- NOT HANDLED\n"));
02218                     break;
02219                 case 0x0C1A: // PR_SENDER_NAME Name of Sender Structure 2
02220                     DEBUG_EMAIL(("Name of Sender Structure 2 -- NOT HANDLED\n"));
02221                     break;
02222                 case 0x0C1B: // PR_SUPPLEMENTARY_INFO
02223                     LIST_COPY_EMAIL_STR("Supplementary info", item->email->supplementary_info);
02224                     break;
02225                 case 0x0C1D: // PR_SENDER_SEARCH_KEY Name of Sender Address 2
02226                     LIST_COPY_EMAIL_STR("Name of Sender Address 2 (Sender search key)", item->email->outlook_sender2);
02227                     break;
02228                 case 0x0C1E: // PR_SENDER_ADDRTYPE Sender Address 2 access method
02229                     LIST_COPY_EMAIL_STR("Sender Address type", item->email->sender2_access);
02230                     break;
02231                 case 0x0C1F: // PR_SENDER_EMAIL_ADDRESS Sender Address 2
02232                     LIST_COPY_EMAIL_STR("Sender Address", item->email->sender2_address);
02233                     break;
02234                 case 0x0C20: // PR_NDR_STATUS_CODE
02235                     LIST_COPY_EMAIL_INT32("NDR status code", item->email->ndr_status_code);
02236                     break;
02237                 case 0x0E01: // PR_DELETE_AFTER_SUBMIT
02238                     LIST_COPY_EMAIL_BOOL("Delete after submit", item->email->delete_after_submit);
02239                     break;
02240                 case 0x0E02: // PR_DISPLAY_BCC BCC Addresses
02241                     LIST_COPY_EMAIL_STR("Display BCC Addresses", item->email->bcc_address);
02242                     break;
02243                 case 0x0E03: // PR_DISPLAY_CC CC Addresses
02244                     LIST_COPY_EMAIL_STR("Display CC Addresses", item->email->cc_address);
02245                     break;
02246                 case 0x0E04: // PR_DISPLAY_TO Address Sent-To
02247                     LIST_COPY_EMAIL_STR("Display Sent-To Address", item->email->sentto_address);
02248                     break;
02249                 case 0x0E06: // PR_MESSAGE_DELIVERY_TIME Date 3 - Email Arrival Date
02250                     LIST_COPY_EMAIL_TIME("Date 3 (Delivery Time)", item->email->arrival_date);
02251                     break;
02252                 case 0x0E07: // PR_MESSAGE_FLAGS Email Flag
02253                     LIST_COPY_EMAIL_INT32("Message Flags", item->flags);
02254                     break;
02255                 case 0x0E08: // PR_MESSAGE_SIZE Total size of a message object
02256                     LIST_COPY_INT32("Message Size", item->message_size);
02257                     break;
02258                 case 0x0E0A: // PR_SENTMAIL_ENTRYID
02259                     // folder that this message is sent to after submission
02260                     LIST_COPY_EMAIL_ENTRYID("Sentmail EntryID", item->email->sentmail_folder);
02261                     break;
02262                 case 0x0E1F: // PR_RTF_IN_SYNC
02263                     // True means that the rtf version is same as text body
02264                     // False means rtf version is more up-to-date than text body
02265                     // if this value doesn't exist, text body is more up-to-date than rtf and
02266                     //   cannot update to the rtf
02267                     LIST_COPY_EMAIL_BOOL("Compressed RTF in Sync", item->email->rtf_in_sync);
02268                     break;
02269                 case 0x0E20: // PR_ATTACH_SIZE binary Attachment data in record
02270                     NULL_CHECK(attach);
02271                     LIST_COPY_INT32("Attachment Size", t);
02272                     attach->data.size = (size_t)t;
02273                     break;
02274                 case 0x0FF9: // PR_RECORD_KEY Record Header 1
02275                     LIST_COPY_BIN(item->record_key);
02276                     DEBUG_EMAIL(("Record Key\n"));
02277                     DEBUG_EMAIL_HEXPRINT(item->record_key.data, item->record_key.size);
02278                     break;
02279                 case 0x1000: // PR_BODY
02280                     LIST_COPY_STR("Plain Text body", item->body);
02281                     break;
02282                 case 0x1001: // PR_REPORT_TEXT
02283                     LIST_COPY_EMAIL_STR("Report Text", item->email->report_text);
02284                     break;
02285                 case 0x1006: // PR_RTF_SYNC_BODY_CRC
02286                     LIST_COPY_EMAIL_INT32("RTF Sync Body CRC", item->email->rtf_body_crc);
02287                     break;
02288                 case 0x1007: // PR_RTF_SYNC_BODY_COUNT
02289                     // a count of the *significant* charcters in the rtf body. Doesn't count
02290                     // whitespace and other ignorable characters
02291                     LIST_COPY_EMAIL_INT32("RTF Sync Body character count", item->email->rtf_body_char_count);
02292                     break;
02293                 case 0x1008: // PR_RTF_SYNC_BODY_TAG
02294                     // the first couple of lines of RTF body so that after modification, then beginning can
02295                     // once again be found
02296                     LIST_COPY_EMAIL_STR("RTF Sync body tag", item->email->rtf_body_tag);
02297                     break;
02298                 case 0x1009: // PR_RTF_COMPRESSED - rtf data is lzw compressed
02299                     LIST_COPY_EMAIL_BIN("RTF Compressed body", item->email->rtf_compressed);
02300                     break;
02301                 case 0x1010: // PR_RTF_SYNC_PREFIX_COUNT
02302                     // a count of the ignored characters before the first significant character
02303                     LIST_COPY_EMAIL_INT32("RTF whitespace prefix count", item->email->rtf_ws_prefix_count);
02304                     break;
02305                 case 0x1011: // PR_RTF_SYNC_TRAILING_COUNT
02306                     // a count of the ignored characters after the last significant character
02307                     LIST_COPY_EMAIL_INT32("RTF whitespace tailing count", item->email->rtf_ws_trailing_count);
02308                     break;
02309                 case 0x1013: // HTML body
02310                     LIST_COPY_EMAIL_STR("HTML body", item->email->htmlbody);
02311                     break;
02312                 case 0x1035: // Message ID
02313                     LIST_COPY_EMAIL_STR("Message ID", item->email->messageid);
02314                     break;
02315                 case 0x1042: // in-reply-to
02316                     LIST_COPY_EMAIL_STR("In-Reply-To", item->email->in_reply_to);
02317                     break;
02318                 case 0x1046: // Return Path - this seems to be the message-id of the rfc822 mail that is being returned
02319                     LIST_COPY_EMAIL_STR("Return Path", item->email->return_path_address);
02320                     break;
02321                 case 0x3001: // PR_DISPLAY_NAME File As
02322                     LIST_COPY_STR("Display Name", item->file_as);
02323                     break;
02324                 case 0x3002: // PR_ADDRTYPE
02325                     LIST_COPY_CONTACT_STR("Address Type", item->contact->address1_transport);
02326                     break;
02327                 case 0x3003: // PR_EMAIL_ADDRESS
02328                     LIST_COPY_CONTACT_STR("Contact email Address", item->contact->address1);
02329                     break;
02330                 case 0x3004: // PR_COMMENT Comment for item - usually folders
02331                     LIST_COPY_STR("Comment", item->comment);
02332                     break;
02333                 case 0x3007: // PR_CREATION_TIME Date 4 - Creation Date?
02334                     LIST_COPY_TIME("Date 4 (Item Creation Date)", item->create_date);
02335                     break;
02336                 case 0x3008: // PR_LAST_MODIFICATION_TIME Date 5 - Modify Date
02337                     LIST_COPY_TIME("Date 5 (Modify Date)", item->modify_date);
02338                     break;
02339                 case 0x300B: // PR_SEARCH_KEY Record Header 2
02340                     DEBUG_EMAIL(("Record Search 2 -- NOT HANDLED\n"));
02341                     break;
02342                 case 0x35DF: // PR_VALID_FOLDER_MASK
02343                     LIST_COPY_STORE_INT32("Valid Folder Mask", item->message_store->valid_mask);
02344                     break;
02345                 case 0x35E0: // PR_IPM_SUBTREE_ENTRYID Top of Personal Folder Record
02346                     LIST_COPY_STORE_ENTRYID("Top of Personal Folder Record", item->message_store->top_of_personal_folder);
02347                     break;
02348                 case 0x35E2: // PR_IPM_OUTBOX_ENTRYID
02349                     LIST_COPY_STORE_ENTRYID("Default Outbox Folder record", item->message_store->default_outbox_folder);
02350                     break;
02351                 case 0x35E3: // PR_IPM_WASTEBASKET_ENTRYID
02352                     LIST_COPY_STORE_ENTRYID("Deleted Items Folder record", item->message_store->deleted_items_folder);
02353                     break;
02354                 case 0x35E4: // PR_IPM_SENTMAIL_ENTRYID
02355                     LIST_COPY_STORE_ENTRYID("Sent Items Folder record", item->message_store->sent_items_folder);
02356                     break;
02357                 case 0x35E5: // PR_VIEWS_ENTRYID
02358                     LIST_COPY_STORE_ENTRYID("User Views Folder record", item->message_store->user_views_folder);
02359                     break;
02360                 case 0x35E6: // PR_COMMON_VIEWS_ENTRYID
02361                     LIST_COPY_STORE_ENTRYID("Common View Folder record", item->message_store->common_view_folder);
02362                     break;
02363                 case 0x35E7: // PR_FINDER_ENTRYID
02364                     LIST_COPY_STORE_ENTRYID("Search Root Folder record", item->message_store->search_root_folder);
02365                     break;
02366                 case 0x3602: // PR_CONTENT_COUNT Number of emails stored in a folder
02367                     LIST_COPY_FOLDER_INT32("Folder Email Count", item->folder->item_count);
02368                     break;
02369                 case 0x3603: // PR_CONTENT_UNREAD Number of unread emails
02370                     LIST_COPY_FOLDER_INT32("Unread Email Count", item->folder->unseen_item_count);
02371                     break;
02372                 case 0x360A: // PR_SUBFOLDERS Has children
02373                     MALLOC_FOLDER(item);
02374                     LIST_COPY_BOOL("Has Subfolders", item->folder->subfolder);
02375                     break;
02376                 case 0x3613: // PR_CONTAINER_CLASS IPF.x
02377                     LIST_COPY_CSTR(item->ascii_type);
02378                     if (pst_strincmp("IPF.Note", item->ascii_type, 8) == 0)
02379                         item->type = PST_TYPE_NOTE;
02380                     else if (pst_stricmp("IPF", item->ascii_type) == 0)
02381                         item->type = PST_TYPE_NOTE;
02382                     else if (pst_strincmp("IPF.Contact", item->ascii_type, 11) == 0)
02383                         item->type = PST_TYPE_CONTACT;
02384                     else if (pst_strincmp("IPF.Journal", item->ascii_type, 11) == 0)
02385                         item->type = PST_TYPE_JOURNAL;
02386                     else if (pst_strincmp("IPF.Appointment", item->ascii_type, 15) == 0)
02387                         item->type = PST_TYPE_APPOINTMENT;
02388                     else if (pst_strincmp("IPF.StickyNote", item->ascii_type, 14) == 0)
02389                         item->type = PST_TYPE_STICKYNOTE;
02390                     else if (pst_strincmp("IPF.Task", item->ascii_type, 8) == 0)
02391                         item->type = PST_TYPE_TASK;
02392                     else
02393                         item->type = PST_TYPE_OTHER;
02394 
02395                     DEBUG_EMAIL(("Container class %s [%"PRIi32"]\n", item->ascii_type, item->type));
02396                     break;
02397                 case 0x3617: // PR_ASSOC_CONTENT_COUNT
02398                     // associated content are items that are attached to this folder
02399                     // but are hidden from users
02400                     LIST_COPY_FOLDER_INT32("Associated Content count", item->folder->assoc_count);
02401                     break;
02402                 case 0x3701: // PR_ATTACH_DATA_OBJ binary data of attachment
02403                     DEBUG_EMAIL(("Binary Data [Size %i] - ", list->elements[x]->size));
02404                     NULL_CHECK(attach);
02405                     if (!list->elements[x]->data) { //special case
02406                         attach->id2_val = list->elements[x]->type;
02407                         DEBUG_EMAIL(("Seen a Reference. The data hasn't been loaded yet. [%#"PRIx64"]\n", attach->id2_val));
02408                     } else {
02409                         LIST_COPY_BIN(attach->data);
02410                     }
02411                     break;
02412                 case 0x3704: // PR_ATTACH_FILENAME Attachment filename (8.3)
02413                     NULL_CHECK(attach);
02414                     LIST_COPY_STR("Attachment Filename", attach->filename1);
02415                     break;
02416                 case 0x3705: // PR_ATTACH_METHOD
02417                     NULL_CHECK(attach);
02418                     LIST_COPY_ENUM("Attachment method", attach->method, 0, 7,
02419                         "No Attachment",
02420                         "Attach By Value",
02421                         "Attach By Reference",
02422                         "Attach by Reference Resolve",
02423                         "Attach by Reference Only",
02424                         "Embedded Message",
02425                         "OLE");
02426                     break;
02427                 case 0x3707: // PR_ATTACH_LONG_FILENAME Attachment filename (long?)
02428                     NULL_CHECK(attach);
02429                     LIST_COPY_STR("Attachment Filename long", attach->filename2);
02430                     break;
02431                 case 0x370B: // PR_RENDERING_POSITION
02432                     // position in characters that the attachment appears in the plain text body
02433                     NULL_CHECK(attach);
02434                     LIST_COPY_INT32("Attachment Position", attach->position);
02435                     break;
02436                 case 0x370E: // PR_ATTACH_MIME_TAG Mime type of encoding
02437                     NULL_CHECK(attach);
02438                     LIST_COPY_STR("Attachment mime encoding", attach->mimetype);
02439                     break;
02440                 case 0x3710: // PR_ATTACH_MIME_SEQUENCE
02441                     // sequence number for mime parts. Includes body
02442                     NULL_CHECK(attach);
02443                     LIST_COPY_INT32("Attachment Mime Sequence", attach->sequence);
02444                     break;
02445                 case 0x3A00: // PR_ACCOUNT
02446                     LIST_COPY_CONTACT_STR("Contact's Account name", item->contact->account_name);
02447                     break;
02448                 case 0x3A01: // PR_ALTERNATE_RECIPIENT
02449                     DEBUG_EMAIL(("Contact Alternate Recipient - NOT PROCESSED\n"));
02450                     break;
02451                 case 0x3A02: // PR_CALLBACK_TELEPHONE_NUMBER
02452                     LIST_COPY_CONTACT_STR("Callback telephone number", item->contact->callback_phone);
02453                     break;
02454                 case 0x3A03: // PR_CONVERSION_PROHIBITED
02455                     LIST_COPY_EMAIL_BOOL("Message Conversion Prohibited", item->email->conversion_prohibited);
02456                     break;
02457                 case 0x3A05: // PR_GENERATION suffix
02458                     LIST_COPY_CONTACT_STR("Contacts Suffix", item->contact->suffix);
02459                     break;
02460                 case 0x3A06: // PR_GIVEN_NAME Contact's first name
02461                     LIST_COPY_CONTACT_STR("Contacts First Name", item->contact->first_name);
02462                     break;
02463                 case 0x3A07: // PR_GOVERNMENT_ID_NUMBER
02464                     LIST_COPY_CONTACT_STR("Contacts Government ID Number", item->contact->gov_id);
02465                     break;
02466                 case 0x3A08: // PR_BUSINESS_TELEPHONE_NUMBER
02467                     LIST_COPY_CONTACT_STR("Business Telephone Number", item->contact->business_phone);
02468                     break;
02469                 case 0x3A09: // PR_HOME_TELEPHONE_NUMBER
02470                     LIST_COPY_CONTACT_STR("Home Telephone Number", item->contact->home_phone);
02471                     break;
02472                 case 0x3A0A: // PR_INITIALS Contact's Initials
02473                     LIST_COPY_CONTACT_STR("Contacts Initials", item->contact->initials);
02474                     break;
02475                 case 0x3A0B: // PR_KEYWORD
02476                     LIST_COPY_CONTACT_STR("Keyword", item->contact->keyword);
02477                     break;
02478                 case 0x3A0C: // PR_LANGUAGE
02479                     LIST_COPY_CONTACT_STR("Contact's Language", item->contact->language);
02480                     break;
02481                 case 0x3A0D: // PR_LOCATION
02482                     LIST_COPY_CONTACT_STR("Contact's Location", item->contact->location);
02483                     break;
02484                 case 0x3A0E: // PR_MAIL_PERMISSION - Can the recipient receive and send email
02485                     LIST_COPY_CONTACT_BOOL("Mail Permission", item->contact->mail_permission);
02486                     break;
02487                 case 0x3A0F: // PR_MHS_COMMON_NAME
02488                     LIST_COPY_CONTACT_STR("MHS Common Name", item->contact->common_name);
02489                     break;
02490                 case 0x3A10: // PR_ORGANIZATIONAL_ID_NUMBER
02491                     LIST_COPY_CONTACT_STR("Organizational ID #", item->contact->org_id);
02492                     break;
02493                 case 0x3A11: // PR_SURNAME Contact's Surname
02494                     LIST_COPY_CONTACT_STR("Contacts Surname", item->contact->surname);
02495                     break;
02496                 case 0x3A12: // PR_ORIGINAL_ENTRY_ID
02497                     DEBUG_EMAIL(("Original Entry ID - NOT PROCESSED\n"));
02498                     break;
02499                 case 0x3A13: // PR_ORIGINAL_DISPLAY_NAME
02500                     DEBUG_EMAIL(("Original Display Name - NOT PROCESSED\n"));
02501                     break;
02502                 case 0x3A14: // PR_ORIGINAL_SEARCH_KEY
02503                     DEBUG_EMAIL(("Original Search Key - NOT PROCESSED\n"));
02504                     break;
02505                 case 0x3A15: // PR_POSTAL_ADDRESS
02506                     LIST_COPY_CONTACT_STR("Default Postal Address", item->contact->def_postal_address);
02507                     break;
02508                 case 0x3A16: // PR_COMPANY_NAME
02509                     LIST_COPY_CONTACT_STR("Company Name", item->contact->company_name);
02510                     break;
02511                 case 0x3A17: // PR_TITLE - Job Title
02512                     LIST_COPY_CONTACT_STR("Job Title", item->contact->job_title);
02513                     break;
02514                 case 0x3A18: // PR_DEPARTMENT_NAME
02515                     LIST_COPY_CONTACT_STR("Department Name", item->contact->department);
02516                     break;
02517                 case 0x3A19: // PR_OFFICE_LOCATION
02518                     LIST_COPY_CONTACT_STR("Office Location", item->contact->office_loc);
02519                     break;
02520                 case 0x3A1A: // PR_PRIMARY_TELEPHONE_NUMBER
02521                     LIST_COPY_CONTACT_STR("Primary Telephone", item->contact->primary_phone);
02522                     break;
02523                 case 0x3A1B: // PR_BUSINESS2_TELEPHONE_NUMBER
02524                     LIST_COPY_CONTACT_STR("Business Phone Number 2", item->contact->business_phone2);
02525                     break;
02526                 case 0x3A1C: // PR_MOBILE_TELEPHONE_NUMBER
02527                     LIST_COPY_CONTACT_STR("Mobile Phone Number", item->contact->mobile_phone);
02528                     break;
02529                 case 0x3A1D: // PR_RADIO_TELEPHONE_NUMBER
02530                     LIST_COPY_CONTACT_STR("Radio Phone Number", item->contact->radio_phone);
02531                     break;
02532                 case 0x3A1E: // PR_CAR_TELEPHONE_NUMBER
02533                     LIST_COPY_CONTACT_STR("Car Phone Number", item->contact->car_phone);
02534                     break;
02535                 case 0x3A1F: // PR_OTHER_TELEPHONE_NUMBER
02536                     LIST_COPY_CONTACT_STR("Other Phone Number", item->contact->other_phone);
02537                     break;
02538                 case 0x3A20: // PR_TRANSMITTABLE_DISPLAY_NAME
02539                     LIST_COPY_CONTACT_STR("Transmittable Display Name", item->contact->transmittable_display_name);
02540                     break;
02541                 case 0x3A21: // PR_PAGER_TELEPHONE_NUMBER
02542                     LIST_COPY_CONTACT_STR("Pager Phone Number", item->contact->pager_phone);
02543                     break;
02544                 case 0x3A22: // PR_USER_CERTIFICATE
02545                     DEBUG_EMAIL(("User Certificate - NOT PROCESSED"));
02546                     break;
02547                 case 0x3A23: // PR_PRIMARY_FAX_NUMBER
02548                     LIST_COPY_CONTACT_STR("Primary Fax Number", item->contact->primary_fax);
02549                     break;
02550                 case 0x3A24: // PR_BUSINESS_FAX_NUMBER
02551                     LIST_COPY_CONTACT_STR("Business Fax Number", item->contact->business_fax);
02552                     break;
02553                 case 0x3A25: // PR_HOME_FAX_NUMBER
02554                     LIST_COPY_CONTACT_STR("Home Fax Number", item->contact->home_fax);
02555                     break;
02556                 case 0x3A26: // PR_BUSINESS_ADDRESS_COUNTRY
02557                     LIST_COPY_CONTACT_STR("Business Address Country", item->contact->business_country);
02558                     break;
02559                 case 0x3A27: // PR_BUSINESS_ADDRESS_CITY
02560                     LIST_COPY_CONTACT_STR("Business Address City", item->contact->business_city);
02561                     break;
02562                 case 0x3A28: // PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE
02563                     LIST_COPY_CONTACT_STR("Business Address State", item->contact->business_state);
02564                     break;
02565                 case 0x3A29: // PR_BUSINESS_ADDRESS_STREET
02566                     LIST_COPY_CONTACT_STR("Business Address Street", item->contact->business_street);
02567                     break;
02568                 case 0x3A2A: // PR_BUSINESS_POSTAL_CODE
02569                     LIST_COPY_CONTACT_STR("Business Postal Code", item->contact->business_postal_code);
02570                     break;
02571                 case 0x3A2B: // PR_BUSINESS_PO_BOX
02572                     LIST_COPY_CONTACT_STR("Business PO Box", item->contact->business_po_box);
02573                     break;
02574                 case 0x3A2C: // PR_TELEX_NUMBER
02575                     LIST_COPY_CONTACT_STR("Telex Number", item->contact->telex);
02576                     break;
02577                 case 0x3A2D: // PR_ISDN_NUMBER
02578                     LIST_COPY_CONTACT_STR("ISDN Number", item->contact->isdn_phone);
02579                     break;
02580                 case 0x3A2E: // PR_ASSISTANT_TELEPHONE_NUMBER
02581                     LIST_COPY_CONTACT_STR("Assistant Phone Number", item->contact->assistant_phone);
02582                     break;
02583                 case 0x3A2F: // PR_HOME2_TELEPHONE_NUMBER
02584                     LIST_COPY_CONTACT_STR("Home Phone 2", item->contact->home_phone2);
02585                     break;
02586                 case 0x3A30: // PR_ASSISTANT
02587                     LIST_COPY_CONTACT_STR("Assistant's Name", item->contact->assistant_name);
02588                     break;
02589                 case 0x3A40: // PR_SEND_RICH_INFO
02590                     LIST_COPY_CONTACT_BOOL("Can receive Rich Text", item->contact->rich_text);
02591                     break;
02592                 case 0x3A41: // PR_WEDDING_ANNIVERSARY
02593                     LIST_COPY_CONTACT_TIME("Wedding Anniversary", item->contact->wedding_anniversary);
02594                     break;
02595                 case 0x3A42: // PR_BIRTHDAY
02596                     LIST_COPY_CONTACT_TIME("Birthday", item->contact->birthday);
02597                     break;
02598                 case 0x3A43: // PR_HOBBIES
02599                     LIST_COPY_CONTACT_STR("Hobbies", item->contact->hobbies);
02600                     break;
02601                 case 0x3A44: // PR_MIDDLE_NAME
02602                     LIST_COPY_CONTACT_STR("Middle Name", item->contact->middle_name);
02603                     break;
02604                 case 0x3A45: // PR_DISPLAY_NAME_PREFIX
02605                     LIST_COPY_CONTACT_STR("Display Name Prefix (Title)", item->contact->display_name_prefix);
02606                     break;
02607                 case 0x3A46: // PR_PROFESSION
02608                     LIST_COPY_CONTACT_STR("Profession", item->contact->profession);
02609                     break;
02610                 case 0x3A47: // PR_PREFERRED_BY_NAME
02611                     LIST_COPY_CONTACT_STR("Preferred By Name", item->contact->pref_name);
02612                     break;
02613                 case 0x3A48: // PR_SPOUSE_NAME
02614                     LIST_COPY_CONTACT_STR("Spouse's Name", item->contact->spouse_name);
02615                     break;
02616                 case 0x3A49: // PR_COMPUTER_NETWORK_NAME
02617                     LIST_COPY_CONTACT_STR("Computer Network Name", item->contact->computer_name);
02618                     break;
02619                 case 0x3A4A: // PR_CUSTOMER_ID
02620                     LIST_COPY_CONTACT_STR("Customer ID", item->contact->customer_id);
02621                     break;
02622                 case 0x3A4B: // PR_TTYTDD_PHONE_NUMBER
02623                     LIST_COPY_CONTACT_STR("TTY/TDD Phone", item->contact->ttytdd_phone);
02624                     break;
02625                 case 0x3A4C: // PR_FTP_SITE
02626                     LIST_COPY_CONTACT_STR("Ftp Site", item->contact->ftp_site);
02627                     break;
02628                 case 0x3A4D: // PR_GENDER
02629                     LIST_COPY_CONTACT_ENUM16("Gender", item->contact->gender, 0, 3, "Unspecified", "Female", "Male");
02630                     break;
02631                 case 0x3A4E: // PR_MANAGER_NAME
02632                     LIST_COPY_CONTACT_STR("Manager's Name", item->contact->manager_name);
02633                     break;
02634                 case 0x3A4F: // PR_NICKNAME
02635                     LIST_COPY_CONTACT_STR("Nickname", item->contact->nickname);
02636                     break;
02637                 case 0x3A50: // PR_PERSONAL_HOME_PAGE
02638                     LIST_COPY_CONTACT_STR("Personal Home Page", item->contact->personal_homepage);
02639                     break;
02640                 case 0x3A51: // PR_BUSINESS_HOME_PAGE
02641                     LIST_COPY_CONTACT_STR("Business Home Page", item->contact->business_homepage);
02642                     break;
02643                 case 0x3A57: // PR_COMPANY_MAIN_PHONE_NUMBER
02644                     LIST_COPY_CONTACT_STR("Company Main Phone", item->contact->company_main_phone);
02645                     break;
02646                 case 0x3A58: // PR_CHILDRENS_NAMES
02647                     DEBUG_EMAIL(("Children's Names - NOT PROCESSED\n"));
02648                     break;
02649                 case 0x3A59: // PR_HOME_ADDRESS_CITY
02650                     LIST_COPY_CONTACT_STR("Home Address City", item->contact->home_city);
02651                     break;
02652                 case 0x3A5A: // PR_HOME_ADDRESS_COUNTRY
02653                     LIST_COPY_CONTACT_STR("Home Address Country", item->contact->home_country);
02654                     break;
02655                 case 0x3A5B: // PR_HOME_ADDRESS_POSTAL_CODE
02656                     LIST_COPY_CONTACT_STR("Home Address Postal Code", item->contact->home_postal_code);
02657                     break;
02658                 case 0x3A5C: // PR_HOME_ADDRESS_STATE_OR_PROVINCE
02659                     LIST_COPY_CONTACT_STR("Home Address State or Province", item->contact->home_state);
02660                     break;
02661                 case 0x3A5D: // PR_HOME_ADDRESS_STREET
02662                     LIST_COPY_CONTACT_STR("Home Address Street", item->contact->home_street);
02663                     break;
02664                 case 0x3A5E: // PR_HOME_ADDRESS_POST_OFFICE_BOX
02665                     LIST_COPY_CONTACT_STR("Home Address Post Office Box", item->contact->home_po_box);
02666                     break;
02667                 case 0x3A5F: // PR_OTHER_ADDRESS_CITY
02668                     LIST_COPY_CONTACT_STR("Other Address City", item->contact->other_city);
02669                     break;
02670                 case 0x3A60: // PR_OTHER_ADDRESS_COUNTRY
02671                     LIST_COPY_CONTACT_STR("Other Address Country", item->contact->other_country);
02672                     break;
02673                 case 0x3A61: // PR_OTHER_ADDRESS_POSTAL_CODE
02674                     LIST_COPY_CONTACT_STR("Other Address Postal Code", item->contact->other_postal_code);
02675                     break;
02676                 case 0x3A62: // PR_OTHER_ADDRESS_STATE_OR_PROVINCE
02677                     LIST_COPY_CONTACT_STR("Other Address State", item->contact->other_state);
02678                     break;
02679                 case 0x3A63: // PR_OTHER_ADDRESS_STREET
02680                     LIST_COPY_CONTACT_STR("Other Address Street", item->contact->other_street);
02681                     break;
02682                 case 0x3A64: // PR_OTHER_ADDRESS_POST_OFFICE_BOX
02683                     LIST_COPY_CONTACT_STR("Other Address Post Office box", item->contact->other_po_box);
02684                     break;
02685                 case 0x3FDE: // PR_INTERNET_CPID
02686                     LIST_COPY_INT32("Internet code page", item->internet_cpid);
02687                     break;
02688                 case 0x3FFD: // PR_MESSAGE_CODEPAGE
02689                     LIST_COPY_INT32("Message code page", item->message_codepage);
02690                     break;
02691                 case 0x65E3: // PR_PREDECESSOR_CHANGE_LIST
02692                     LIST_COPY_BIN(item->predecessor_change);
02693                     DEBUG_EMAIL(("Predecessor Change\n"));
02694                     DEBUG_EMAIL_HEXPRINT(item->predecessor_change.data, item->predecessor_change.size);
02695                     break;
02696                 case 0x67F2: // ID2 value of the attachments proper record
02697                     DEBUG_EMAIL(("Attachment ID2 value - "));
02698                     if (attach) {
02699                         uint32_t tempid;
02700                         memcpy(&(tempid), list->elements[x]->data, sizeof(tempid));
02701                         LE32_CPU(tempid);
02702                         attach->id2_val = tempid;
02703                         DEBUG_EMAIL(("%#"PRIx64"\n", attach->id2_val));
02704                     } else {
02705                         DEBUG_EMAIL(("NOT AN ATTACHMENT: %#x\n", list->elements[x]->mapi_id));
02706                     }
02707                     break;
02708                 case 0x67FF: // Extra Property Identifier (Password CheckSum)
02709                     LIST_COPY_STORE_INT32("Password checksum", item->message_store->pwd_chksum);
02710                     break;
02711                 case 0x6F02: // Secure HTML Body
02712                     LIST_COPY_EMAIL_BIN("Secure HTML Body", item->email->encrypted_htmlbody);
02713                     break;
02714                 case 0x6F04: // Secure Text Body
02715                     LIST_COPY_EMAIL_BIN("Secure Text Body", item->email->encrypted_body);
02716                     break;
02717                 case 0x7C07: // top of folders ENTRYID
02718                     LIST_COPY_STORE_ENTRYID("Top of folders RecID", item->message_store->top_of_folder);
02719                     break;
02720                 case 0x8005: // Contact's Fullname
02721                     LIST_COPY_CONTACT_STR("Contact Fullname", item->contact->fullname);
02722                     break;
02723                 case 0x801A: // Full Home Address
02724                     LIST_COPY_CONTACT_STR("Home Address", item->contact->home_address);
02725                     break;
02726                 case 0x801B: // Full Business Address
02727                     LIST_COPY_CONTACT_STR("Business Address", item->contact->business_address);
02728                     break;
02729                 case 0x801C: // Full Other Address
02730                     LIST_COPY_CONTACT_STR("Other Address", item->contact->other_address);
02731                     break;
02732                 case 0x8045: // Work address street
02733                     LIST_COPY_CONTACT_STR("Work address street", item->contact->work_address_street);
02734                     break;
02735                 case 0x8046: // Work address city
02736                     LIST_COPY_CONTACT_STR("Work address city", item->contact->work_address_city);
02737                     break;
02738                 case 0x8047: // Work address state
02739                     LIST_COPY_CONTACT_STR("Work address state", item->contact->work_address_state);
02740                     break;
02741                 case 0x8048: // Work address postalcode
02742                     LIST_COPY_CONTACT_STR("Work address postalcode", item->contact->work_address_postalcode);
02743                     break;
02744                 case 0x8049: // Work address country
02745                     LIST_COPY_CONTACT_STR("Work address country", item->contact->work_address_country);
02746                     break;
02747                 case 0x804A: // Work address postofficebox
02748                     LIST_COPY_CONTACT_STR("Work address postofficebox", item->contact->work_address_postofficebox);
02749                     break;
02750                 case 0x8082: // Email Address 1 Transport
02751                     LIST_COPY_CONTACT_STR("Email Address 1 Transport", item->contact->address1_transport);
02752                     break;
02753                 case 0x8083: // Email Address 1 Address
02754                     LIST_COPY_CONTACT_STR("Email Address 1 Address", item->contact->address1);
02755                     break;
02756                 case 0x8084: // Email Address 1 Description
02757                     LIST_COPY_CONTACT_STR("Email Address 1 Description", item->contact->address1_desc);
02758                     break;
02759                 case 0x8085: // Email Address 1 Record
02760                     LIST_COPY_CONTACT_STR("Email Address 1 Record", item->contact->address1a);
02761                     break;
02762                 case 0x8092: // Email Address 2 Transport
02763                     LIST_COPY_CONTACT_STR("Email Address 2 Transport", item->contact->address2_transport);
02764                     break;
02765                 case 0x8093: // Email Address 2 Address
02766                     LIST_COPY_CONTACT_STR("Email Address 2 Address", item->contact->address2);
02767                     break;
02768                 case 0x8094: // Email Address 2 Description
02769                     LIST_COPY_CONTACT_STR("Email Address 2 Description", item->contact->address2_desc);
02770                     break;
02771                 case 0x8095: // Email Address 2 Record
02772                     LIST_COPY_CONTACT_STR("Email Address 2 Record", item->contact->address2a);
02773                     break;
02774                 case 0x80A2: // Email Address 3 Transport
02775                     LIST_COPY_CONTACT_STR("Email Address 3 Transport", item->contact->address3_transport);
02776                     break;
02777                 case 0x80A3: // Email Address 3 Address
02778                     LIST_COPY_CONTACT_STR("Email Address 3 Address", item->contact->address3);
02779                     break;
02780                 case 0x80A4: // Email Address 3 Description
02781                     LIST_COPY_CONTACT_STR("Email Address 3 Description", item->contact->address3_desc);
02782                     break;
02783                 case 0x80A5: // Email Address 3 Record
02784                     LIST_COPY_CONTACT_STR("Email Address 3 Record", item->contact->address3a);
02785                     break;
02786                 case 0x80D8: // Internet Free/Busy
02787                     LIST_COPY_CONTACT_STR("Internet Free/Busy", item->contact->free_busy_address);
02788                     break;
02789                 case 0x8205: // Show on Free/Busy as
02790                     LIST_COPY_APPT_ENUM("Appointment shows as", item->appointment->showas, 0, 4,
02791                         "Free", "Tentative", "Busy", "Out Of Office");
02792                     break;
02793                 case 0x8208: // Location of an appointment
02794                     LIST_COPY_APPT_STR("Appointment Location", item->appointment->location);
02795                     break;
02796                 case 0x820d: // Appointment start
02797                     LIST_COPY_APPT_TIME("Appointment Date Start", item->appointment->start);
02798                     break;
02799                 case 0x820e: // Appointment end
02800                     LIST_COPY_APPT_TIME("Appointment Date End", item->appointment->end);
02801                     break;
02802                 case 0x8214: // Label for an appointment
02803                     LIST_COPY_APPT_ENUM("Label for appointment", item->appointment->label, 0, 11,
02804                         "None",
02805                         "Important",
02806                         "Business",
02807                         "Personal",
02808                         "Vacation",
02809                         "Must Attend",
02810                         "Travel Required",
02811                         "Needs Preparation",
02812                         "Birthday",
02813                         "Anniversary",
02814                         "Phone Call");
02815                     break;
02816                 case 0x8215: // All day appointment flag
02817                     LIST_COPY_APPT_BOOL("All day flag", item->appointment->all_day);
02818                     break;
02819                 case 0x8231: // Recurrence type
02820                     LIST_COPY_APPT_ENUM("Appointment reccurence", item->appointment->recurrence_type, 0, 5,
02821                         "None",
02822                         "Daily",
02823                         "Weekly",
02824                         "Monthly",
02825                         "Yearly");
02826                     break;
02827                 case 0x8232: // Recurrence description
02828                     LIST_COPY_APPT_STR("Appointment recurrence description", item->appointment->recurrence);
02829                     break;
02830                 case 0x8234: // TimeZone as String
02831                     LIST_COPY_APPT_STR("TimeZone of times", item->appointment->timezonestring);
02832                     break;
02833                 case 0x8235: // Recurrence start date
02834                     LIST_COPY_APPT_TIME("Recurrence Start Date", item->appointment->recurrence_start);
02835                     break;
02836                 case 0x8236: // Recurrence end date
02837                     LIST_COPY_APPT_TIME("Recurrence End Date", item->appointment->recurrence_end);
02838                     break;
02839                 case 0x8501: // Reminder minutes before appointment start
02840                     LIST_COPY_APPT_INT32("Alarm minutes", item->appointment->alarm_minutes);
02841                     break;
02842                 case 0x8503: // Reminder alarm
02843                     LIST_COPY_APPT_BOOL("Reminder alarm", item->appointment->alarm);
02844                     break;
02845                 case 0x8516: // Common start
02846                     DEBUG_EMAIL(("Common Start Date - %s\n", fileTimeToAscii((FILETIME*)list->elements[x]->data)));
02847                     break;
02848                 case 0x8517: // Common end
02849                     DEBUG_EMAIL(("Common End Date - %s\n", fileTimeToAscii((FILETIME*)list->elements[x]->data)));
02850                     break;
02851                 case 0x851f: // Play reminder sound filename
02852                     LIST_COPY_APPT_STR("Appointment reminder sound filename", item->appointment->alarm_filename);
02853                     break;
02854                 case 0x8530: // Followup
02855                     LIST_COPY_CONTACT_STR("Followup String", item->contact->followup);
02856                     break;
02857                 case 0x8534: // Mileage
02858                     LIST_COPY_CONTACT_STR("Mileage", item->contact->mileage);
02859                     break;
02860                 case 0x8535: // Billing Information
02861                     LIST_COPY_CONTACT_STR("Billing Information", item->contact->billing_information);
02862                     break;
02863                 case 0x8554: // Outlook Version
02864                     LIST_COPY_STR("Outlook Version", item->outlook_version);
02865                     break;
02866                 case 0x8560: // Appointment Reminder Time
02867                     LIST_COPY_APPT_TIME("Appointment Reminder Time", item->appointment->reminder);
02868                     break;
02869                 case 0x8700: // Journal Type
02870                     LIST_COPY_JOURNAL_STR("Journal Entry Type", item->journal->type);
02871                     break;
02872                 case 0x8706: // Journal Start date/time
02873                     LIST_COPY_JOURNAL_TIME("Start Timestamp", item->journal->start);
02874                     break;
02875                 case 0x8708: // Journal End date/time
02876                     LIST_COPY_JOURNAL_TIME("End Timestamp", item->journal->end);
02877                     break;
02878                 case 0x8712: // Journal Type Description
02879                     LIST_COPY_JOURNAL_STR("Journal description", item->journal->description);
02880                     break;
02881                 default:
02882                     if (list->elements[x]->type == (uint32_t)0x0002) {
02883                         DEBUG_EMAIL(("Unknown type %#x 16bit int = %hi\n", list->elements[x]->mapi_id,
02884                             *(int16_t*)list->elements[x]->data));
02885 
02886                     } else if (list->elements[x]->type == (uint32_t)0x0003) {
02887                         DEBUG_EMAIL(("Unknown type %#x 32bit int = %i\n", list->elements[x]->mapi_id,
02888                             *(int32_t*)list->elements[x]->data));
02889 
02890                     } else if (list->elements[x]->type == (uint32_t)0x0004) {
02891                         DEBUG_EMAIL(("Unknown type %#x 4-byte floating [size = %#x]\n", list->elements[x]->mapi_id,
02892                             list->elements[x]->size));
02893                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02894 
02895                     } else if (list->elements[x]->type == (uint32_t)0x0005) {
02896                         DEBUG_EMAIL(("Unknown type %#x double floating [size = %#x]\n", list->elements[x]->mapi_id,
02897                             list->elements[x]->size));
02898                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02899 
02900                     } else if (list->elements[x]->type == (uint32_t)0x0006) {
02901                         DEBUG_EMAIL(("Unknown type %#x signed 64bit int = %"PRIi64"\n", list->elements[x]->mapi_id,
02902                             *(int64_t*)list->elements[x]->data));
02903                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02904 
02905                     } else if (list->elements[x]->type == (uint32_t)0x0007) {
02906                         DEBUG_EMAIL(("Unknown type %#x application time [size = %#x]\n", list->elements[x]->mapi_id,
02907                             list->elements[x]->size));
02908                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02909 
02910                     } else if (list->elements[x]->type == (uint32_t)0x000a) {
02911                         DEBUG_EMAIL(("Unknown type %#x 32bit error value = %i\n", list->elements[x]->mapi_id,
02912                             *(int32_t*)list->elements[x]->data));
02913 
02914                     } else if (list->elements[x]->type == (uint32_t)0x000b) {
02915                         DEBUG_EMAIL(("Unknown type %#x 16bit boolean = %s [%hi]\n", list->elements[x]->mapi_id,
02916                             (*((int16_t*)list->elements[x]->data)!=0?"True":"False"),
02917                             *((int16_t*)list->elements[x]->data)));
02918 
02919                     } else if (list->elements[x]->type == (uint32_t)0x000d) {
02920                         DEBUG_EMAIL(("Unknown type %#x Embedded object [size = %#x]\n", list->elements[x]->mapi_id,
02921                             list->elements[x]->size));
02922                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02923 
02924                     } else if (list->elements[x]->type == (uint32_t)0x0014) {
02925                         DEBUG_EMAIL(("Unknown type %#x signed 64bit int = %"PRIi64"\n", list->elements[x]->mapi_id,
02926                             *(int64_t*)list->elements[x]->data));
02927                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02928 
02929                     } else if (list->elements[x]->type == (uint32_t)0x001e) {
02930                         DEBUG_EMAIL(("Unknown type %#x String Data = \"%s\"\n", list->elements[x]->mapi_id,
02931                             list->elements[x]->data));
02932 
02933                     } else if (list->elements[x]->type == (uint32_t)0x001f) {
02934                         DEBUG_EMAIL(("Unknown type %#x Unicode String Data [size = %#x]\n", list->elements[x]->mapi_id,
02935                             list->elements[x]->size));
02936                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02937 
02938                     } else if (list->elements[x]->type == (uint32_t)0x0040) {
02939                         DEBUG_EMAIL(("Unknown type %#x Date = \"%s\"\n", list->elements[x]->mapi_id,
02940                             fileTimeToAscii((FILETIME*)list->elements[x]->data)));
02941 
02942                     } else if (list->elements[x]->type == (uint32_t)0x0048) {
02943                         DEBUG_EMAIL(("Unknown type %#x OLE GUID [size = %#x]\n", list->elements[x]->mapi_id,
02944                             list->elements[x]->size));
02945                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02946 
02947                     } else if (list->elements[x]->type == (uint32_t)0x0102) {
02948                         DEBUG_EMAIL(("Unknown type %#x Binary Data [size = %#x]\n", list->elements[x]->mapi_id,
02949                             list->elements[x]->size));
02950                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02951 
02952                     } else if (list->elements[x]->type == (uint32_t)0x1003) {
02953                         DEBUG_EMAIL(("Unknown type %#x Array of 32 bit values [size = %#x]\n", list->elements[x]->mapi_id,
02954                             list->elements[x]->size));
02955                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02956 
02957                     } else if (list->elements[x]->type == (uint32_t)0x1014) {
02958                         DEBUG_EMAIL(("Unknown type %#x Array of 64 bit values [siize = %#x]\n", list->elements[x]->mapi_id,
02959                             list->elements[x]->size));
02960                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02961 
02962                     } else if (list->elements[x]->type == (uint32_t)0x101e) {
02963                         DEBUG_EMAIL(("Unknown type %#x Array of Strings [size = %#x]\n", list->elements[x]->mapi_id,
02964                             list->elements[x]->size));
02965                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02966 
02967                     } else if (list->elements[x]->type == (uint32_t)0x101f) {
02968                         DEBUG_EMAIL(("Unknown type %#x Array of Unicode Strings [size = %#x]\n", list->elements[x]->mapi_id,
02969                             list->elements[x]->size));
02970                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02971 
02972                     } else if (list->elements[x]->type == (uint32_t)0x1102) {
02973                         DEBUG_EMAIL(("Unknown type %#x Array of binary data blobs [size = %#x]\n", list->elements[x]->mapi_id,
02974                             list->elements[x]->size));
02975                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02976 
02977                     } else {
02978                         DEBUG_EMAIL(("Unknown type %#x Not Printable [%#x]\n", list->elements[x]->mapi_id,
02979                             list->elements[x]->type));
02980                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02981                     }
02982 
02983                     if (list->elements[x]->data) {
02984                         free(list->elements[x]->data);
02985                         list->elements[x]->data = NULL;
02986                     }
02987             }
02988         }
02989         list = list->next;
02990         if (attach) attach = attach->next;
02991     }
02992     DEBUG_RET();
02993     return 0;
02994 }
02995 
02996 
02997 void pst_free_list(pst_mapi_object *list) {
02998     pst_mapi_object *l;
02999     DEBUG_ENT("pst_free_list");
03000     while (list) {
03001         if (list->elements) {
03002             int32_t x;
03003             for (x=0; x < list->orig_count; x++) {
03004                 if (list->elements[x]) {
03005                     if (list->elements[x]->data) free(list->elements[x]->data);
03006                     free(list->elements[x]);
03007                 }
03008             }
03009             free(list->elements);
03010         }
03011         l = list->next;
03012         free (list);
03013         list = l;
03014     }
03015     DEBUG_RET();
03016 }
03017 
03018 
03019 void pst_free_id2(pst_id2_ll * head) {
03020     pst_id2_ll *t;
03021     DEBUG_ENT("pst_free_id2");
03022     while (head) {
03023         if (head->child) pst_free_id2(head->child);
03024         t = head->next;
03025         free(head);
03026         head = t;
03027     }
03028     DEBUG_RET();
03029 }
03030 
03031 
03032 void pst_free_id (pst_index_ll *head) {
03033     pst_index_ll *t;
03034     DEBUG_ENT("pst_free_id");
03035     while (head) {
03036         t = head->next;
03037         free(head);
03038         head = t;
03039     }
03040     DEBUG_RET();
03041 }
03042 
03043 
03044 void pst_free_desc (pst_desc_ll *head) {
03045     pst_desc_ll *t;
03046     DEBUG_ENT("pst_free_desc");
03047     while (head) {
03048         while (head->child) {
03049             head = head->child;
03050         }
03051 
03052         // point t to the next item
03053         t = head->next;
03054         if (!t && head->parent) {
03055             t = head->parent;
03056             t->child = NULL; // set the child to NULL so we don't come back here again!
03057         }
03058 
03059         if (head) free(head);
03060         else      DIE(("head is NULL"));
03061 
03062         head = t;
03063     }
03064     DEBUG_RET();
03065 }
03066 
03067 
03068 void pst_free_xattrib(pst_x_attrib_ll *x) {
03069     pst_x_attrib_ll *t;
03070     DEBUG_ENT("pst_free_xattrib");
03071     while (x) {
03072         if (x->data) free(x->data);
03073         t = x->next;
03074         free(x);
03075         x = t;
03076     }
03077     DEBUG_RET();
03078 }
03079 
03080 
03081 pst_id2_ll * pst_build_id2(pst_file *pf, pst_index_ll* list) {
03082     pst_block_header block_head;
03083     pst_id2_ll *head = NULL, *tail = NULL;
03084     uint16_t x = 0;
03085     char *b_ptr = NULL;
03086     char *buf = NULL;
03087     pst_id2_assoc id2_rec;
03088     pst_index_ll *i_ptr = NULL;
03089     pst_id2_ll *i2_ptr = NULL;
03090     DEBUG_ENT("pst_build_id2");
03091 
03092     if (pst_read_block_size(pf, list->offset, list->size, &buf) < list->size) {
03093         //an error occured in block read
03094         WARN(("block read error occured. offset = %#"PRIx64", size = %#"PRIx64"\n", list->offset, list->size));
03095         if (buf) free(buf);
03096         DEBUG_RET();
03097         return NULL;
03098     }
03099     DEBUG_HEXDUMPC(buf, list->size, 16);
03100 
03101     memcpy(&block_head, buf, sizeof(block_head));
03102     LE16_CPU(block_head.type);
03103     LE16_CPU(block_head.count);
03104 
03105     if (block_head.type != (uint16_t)0x0002) { // some sort of constant?
03106         WARN(("Unknown constant [%#hx] at start of id2 values [offset %#"PRIx64"].\n", block_head.type, list->offset));
03107         if (buf) free(buf);
03108         DEBUG_RET();
03109         return NULL;
03110     }
03111 
03112     DEBUG_INDEX(("ID %#"PRIx64" is likely to be a description record. Count is %i (offset %#"PRIx64")\n",
03113             list->i_id, block_head.count, list->offset));
03114     x = 0;
03115     b_ptr = buf + ((pf->do_read64) ? 0x08 : 0x04);
03116     while (x < block_head.count) {
03117         b_ptr += pst_decode_assoc(pf, &id2_rec, b_ptr);
03118         DEBUG_INDEX(("id2 = %#x, id = %#"PRIx64", child id = %#"PRIx64"\n", id2_rec.id2, id2_rec.id, id2_rec.child_id));
03119         if ((i_ptr = pst_getID(pf, id2_rec.id)) == NULL) {
03120             DEBUG_WARN(("%#"PRIx64" - Not Found\n", id2_rec.id));
03121         } else {
03122             DEBUG_INDEX(("%#"PRIx64" - Offset %#"PRIx64", u1 %#"PRIx64", Size %"PRIi64"(%#"PRIx64")\n",
03123                          i_ptr->i_id, i_ptr->offset, i_ptr->u1, i_ptr->size, i_ptr->size));
03124             // add it to the tree
03125             i2_ptr = (pst_id2_ll*) xmalloc(sizeof(pst_id2_ll));
03126             i2_ptr->id2   = id2_rec.id2;
03127             i2_ptr->id    = i_ptr;
03128             i2_ptr->child = NULL;
03129             i2_ptr->next  = NULL;
03130             if (!head) head = i2_ptr;
03131             if (tail)  tail->next = i2_ptr;
03132             tail = i2_ptr;
03133             if (id2_rec.child_id) {
03134                 if ((i_ptr = pst_getID(pf, id2_rec.child_id)) == NULL) {
03135                     DEBUG_WARN(("child id [%#"PRIi64"] not found\n", id2_rec.child_id));
03136                 }
03137                 else {
03138                     i2_ptr->child = pst_build_id2(pf, i_ptr);
03139                 }
03140             }
03141         }
03142         x++;
03143     }
03144     if (buf) free (buf);
03145     DEBUG_RET();
03146     return head;
03147 }
03148 
03149 
03150 void pst_free_attach(pst_item_attach *attach) {
03151     while (attach) {
03152         pst_item_attach *t;
03153         SAFE_FREE_STR(attach->filename1);
03154         SAFE_FREE_STR(attach->filename2);
03155         SAFE_FREE_STR(attach->mimetype);
03156         SAFE_FREE_BIN(attach->data);
03157         pst_free_id2(attach->id2_head);
03158         t = attach->next;
03159         free(attach);
03160         attach = t;
03161     }
03162 }
03163 
03164 
03165 void pst_freeItem(pst_item *item) {
03166     pst_item_extra_field *et;
03167 
03168     DEBUG_ENT("pst_freeItem");
03169     if (item) {
03170         if (item->email) {
03171             SAFE_FREE(item->email->arrival_date);
03172             SAFE_FREE_STR(item->email->cc_address);
03173             SAFE_FREE_STR(item->email->bcc_address);
03174             SAFE_FREE_BIN(item->email->conversation_index);
03175             SAFE_FREE_BIN(item->email->encrypted_body);
03176             SAFE_FREE_BIN(item->email->encrypted_htmlbody);
03177             SAFE_FREE_STR(item->email->header);
03178             SAFE_FREE_STR(item->email->htmlbody);
03179             SAFE_FREE_STR(item->email->in_reply_to);
03180             SAFE_FREE_STR(item->email->messageid);
03181             SAFE_FREE_STR(item->email->original_bcc);
03182             SAFE_FREE_STR(item->email->original_cc);
03183             SAFE_FREE_STR(item->email->original_to);
03184             SAFE_FREE_STR(item->email->outlook_recipient);
03185             SAFE_FREE_STR(item->email->outlook_recipient_name);
03186             SAFE_FREE_STR(item->email->outlook_recipient2);
03187             SAFE_FREE_STR(item->email->outlook_sender);
03188             SAFE_FREE_STR(item->email->outlook_sender_name);
03189             SAFE_FREE_STR(item->email->outlook_sender2);
03190             SAFE_FREE_STR(item->email->processed_subject);
03191             SAFE_FREE_STR(item->email->recip_access);
03192             SAFE_FREE_STR(item->email->recip_address);
03193             SAFE_FREE_STR(item->email->recip2_access);
03194             SAFE_FREE_STR(item->email->recip2_address);
03195             SAFE_FREE_STR(item->email->reply_to);
03196             SAFE_FREE_STR(item->email->rtf_body_tag);
03197             SAFE_FREE_BIN(item->email->rtf_compressed);
03198             SAFE_FREE_STR(item->email->return_path_address);
03199             SAFE_FREE_STR(item->email->sender_access);
03200             SAFE_FREE_STR(item->email->sender_address);
03201             SAFE_FREE_STR(item->email->sender2_access);
03202             SAFE_FREE_STR(item->email->sender2_address);
03203             SAFE_FREE(item->email->sent_date);
03204             SAFE_FREE(item->email->sentmail_folder);
03205             SAFE_FREE_STR(item->email->sentto_address);
03206             SAFE_FREE_STR(item->email->report_text);
03207             SAFE_FREE(item->email->report_time);
03208             SAFE_FREE_STR(item->email->supplementary_info);
03209             free(item->email);
03210         }
03211         if (item->folder) {
03212             free(item->folder);
03213         }
03214         if (item->message_store) {
03215             SAFE_FREE(item->message_store->top_of_personal_folder);
03216             SAFE_FREE(item->message_store->default_outbox_folder);
03217             SAFE_FREE(item->message_store->deleted_items_folder);
03218             SAFE_FREE(item->message_store->sent_items_folder);
03219             SAFE_FREE(item->message_store->user_views_folder);
03220             SAFE_FREE(item->message_store->common_view_folder);
03221             SAFE_FREE(item->message_store->search_root_folder);
03222             SAFE_FREE(item->message_store->top_of_folder);
03223             free(item->message_store);
03224         }
03225         if (item->contact) {
03226             SAFE_FREE_STR(item->contact->access_method);
03227             SAFE_FREE_STR(item->contact->account_name);
03228             SAFE_FREE_STR(item->contact->address1);
03229             SAFE_FREE_STR(item->contact->address1a);
03230             SAFE_FREE_STR(item->contact->address1_desc);
03231             SAFE_FREE_STR(item->contact->address1_transport);
03232             SAFE_FREE_STR(item->contact->address2);
03233             SAFE_FREE_STR(item->contact->address2a);
03234             SAFE_FREE_STR(item->contact->address2_desc);
03235             SAFE_FREE_STR(item->contact->address2_transport);
03236             SAFE_FREE_STR(item->contact->address3);
03237             SAFE_FREE_STR(item->contact->address3a);
03238             SAFE_FREE_STR(item->contact->address3_desc);
03239             SAFE_FREE_STR(item->contact->address3_transport);
03240             SAFE_FREE_STR(item->contact->assistant_name);
03241             SAFE_FREE_STR(item->contact->assistant_phone);
03242             SAFE_FREE_STR(item->contact->billing_information);
03243             SAFE_FREE(item->contact->birthday);
03244             SAFE_FREE_STR(item->contact->business_address);
03245             SAFE_FREE_STR(item->contact->business_city);
03246             SAFE_FREE_STR(item->contact->business_country);
03247             SAFE_FREE_STR(item->contact->business_fax);
03248             SAFE_FREE_STR(item->contact->business_homepage);
03249             SAFE_FREE_STR(item->contact->business_phone);
03250             SAFE_FREE_STR(item->contact->business_phone2);
03251             SAFE_FREE_STR(item->contact->business_po_box);
03252             SAFE_FREE_STR(item->contact->business_postal_code);
03253             SAFE_FREE_STR(item->contact->business_state);
03254             SAFE_FREE_STR(item->contact->business_street);
03255             SAFE_FREE_STR(item->contact->callback_phone);
03256             SAFE_FREE_STR(item->contact->car_phone);
03257             SAFE_FREE_STR(item->contact->company_main_phone);
03258             SAFE_FREE_STR(item->contact->company_name);
03259             SAFE_FREE_STR(item->contact->computer_name);
03260             SAFE_FREE_STR(item->contact->customer_id);
03261             SAFE_FREE_STR(item->contact->def_postal_address);
03262             SAFE_FREE_STR(item->contact->department);
03263             SAFE_FREE_STR(item->contact->display_name_prefix);
03264             SAFE_FREE_STR(item->contact->first_name);
03265             SAFE_FREE_STR(item->contact->followup);
03266             SAFE_FREE_STR(item->contact->free_busy_address);
03267             SAFE_FREE_STR(item->contact->ftp_site);
03268             SAFE_FREE_STR(item->contact->fullname);
03269             SAFE_FREE_STR(item->contact->gov_id);
03270             SAFE_FREE_STR(item->contact->hobbies);
03271             SAFE_FREE_STR(item->contact->home_address);
03272             SAFE_FREE_STR(item->contact->home_city);
03273             SAFE_FREE_STR(item->contact->home_country);
03274             SAFE_FREE_STR(item->contact->home_fax);
03275             SAFE_FREE_STR(item->contact->home_po_box);
03276             SAFE_FREE_STR(item->contact->home_phone);
03277             SAFE_FREE_STR(item->contact->home_phone2);
03278             SAFE_FREE_STR(item->contact->home_postal_code);
03279             SAFE_FREE_STR(item->contact->home_state);
03280             SAFE_FREE_STR(item->contact->home_street);
03281             SAFE_FREE_STR(item->contact->initials);
03282             SAFE_FREE_STR(item->contact->isdn_phone);
03283             SAFE_FREE_STR(item->contact->job_title);
03284             SAFE_FREE_STR(item->contact->keyword);
03285             SAFE_FREE_STR(item->contact->language);
03286             SAFE_FREE_STR(item->contact->location);
03287             SAFE_FREE_STR(item->contact->manager_name);
03288             SAFE_FREE_STR(item->contact->middle_name);
03289             SAFE_FREE_STR(item->contact->mileage);
03290             SAFE_FREE_STR(item->contact->mobile_phone);
03291             SAFE_FREE_STR(item->contact->nickname);
03292             SAFE_FREE_STR(item->contact->office_loc);
03293             SAFE_FREE_STR(item->contact->common_name);
03294             SAFE_FREE_STR(item->contact->org_id);
03295             SAFE_FREE_STR(item->contact->other_address);
03296             SAFE_FREE_STR(item->contact->other_city);
03297             SAFE_FREE_STR(item->contact->other_country);
03298             SAFE_FREE_STR(item->contact->other_phone);
03299             SAFE_FREE_STR(item->contact->other_po_box);
03300             SAFE_FREE_STR(item->contact->other_postal_code);
03301             SAFE_FREE_STR(item->contact->other_state);
03302             SAFE_FREE_STR(item->contact->other_street);
03303             SAFE_FREE_STR(item->contact->pager_phone);
03304             SAFE_FREE_STR(item->contact->personal_homepage);
03305             SAFE_FREE_STR(item->contact->pref_name);
03306             SAFE_FREE_STR(item->contact->primary_fax);
03307             SAFE_FREE_STR(item->contact->primary_phone);
03308             SAFE_FREE_STR(item->contact->profession);
03309             SAFE_FREE_STR(item->contact->radio_phone);
03310             SAFE_FREE_STR(item->contact->spouse_name);
03311             SAFE_FREE_STR(item->contact->suffix);
03312             SAFE_FREE_STR(item->contact->surname);
03313             SAFE_FREE_STR(item->contact->telex);
03314             SAFE_FREE_STR(item->contact->transmittable_display_name);
03315             SAFE_FREE_STR(item->contact->ttytdd_phone);
03316             SAFE_FREE(item->contact->wedding_anniversary);
03317             SAFE_FREE_STR(item->contact->work_address_street);
03318             SAFE_FREE_STR(item->contact->work_address_city);
03319             SAFE_FREE_STR(item->contact->work_address_state);
03320             SAFE_FREE_STR(item->contact->work_address_postalcode);
03321             SAFE_FREE_STR(item->contact->work_address_country);
03322             SAFE_FREE_STR(item->contact->work_address_postofficebox);
03323             free(item->contact);
03324         }
03325 
03326         pst_free_attach(item->attach);
03327 
03328         while (item->extra_fields) {
03329             SAFE_FREE(item->extra_fields->field_name);
03330             SAFE_FREE(item->extra_fields->value);
03331             et = item->extra_fields->next;
03332             free(item->extra_fields);
03333             item->extra_fields = et;
03334         }
03335         if (item->journal) {
03336             SAFE_FREE(item->journal->end);
03337             SAFE_FREE(item->journal->start);
03338             SAFE_FREE_STR(item->journal->type);
03339             free(item->journal);
03340         }
03341         if (item->appointment) {
03342             SAFE_FREE_STR(item->appointment->location);
03343             SAFE_FREE(item->appointment->reminder);
03344             SAFE_FREE_STR(item->appointment->alarm_filename);
03345             SAFE_FREE(item->appointment->start);
03346             SAFE_FREE(item->appointment->end);
03347             SAFE_FREE_STR(item->appointment->timezonestring);
03348             SAFE_FREE_STR(item->appointment->recurrence);
03349             SAFE_FREE(item->appointment->recurrence_start);
03350             SAFE_FREE(item->appointment->recurrence_end);
03351             free(item->appointment);
03352         }
03353         SAFE_FREE(item->ascii_type);
03354         SAFE_FREE_STR(item->body_charset);
03355         SAFE_FREE_STR(item->body);
03356         SAFE_FREE_STR(item->subject);
03357         SAFE_FREE_STR(item->comment);
03358         SAFE_FREE(item->create_date);
03359         SAFE_FREE_STR(item->file_as);
03360         SAFE_FREE(item->modify_date);
03361         SAFE_FREE_STR(item->outlook_version);
03362         SAFE_FREE_BIN(item->record_key);
03363         SAFE_FREE_BIN(item->predecessor_change);
03364         free(item);
03365     }
03366     DEBUG_RET();
03367 }
03368 
03369 
03376 int pst_getBlockOffsetPointer(pst_file *pf, pst_id2_ll *i2_head, pst_subblocks *subblocks, uint32_t offset, pst_block_offset_pointer *p) {
03377     size_t size;
03378     pst_block_offset block_offset;
03379     DEBUG_ENT("pst_getBlockOffsetPointer");
03380     if (p->needfree) free(p->from);
03381     p->from     = NULL;
03382     p->to       = NULL;
03383     p->needfree = 0;
03384     if (!offset) {
03385         // no data
03386         p->from = p->to = NULL;
03387     }
03388     else if ((offset & 0xf) == (uint32_t)0xf) {
03389         // external index reference
03390         DEBUG_WARN(("Found id2 %#x value. Will follow it\n", offset));
03391         size = pst_ff_getID2block(pf, offset, i2_head, &(p->from));
03392         if (size) {
03393             p->to = p->from + size;
03394             p->needfree = 1;
03395         }
03396         else {
03397             if (p->from) {
03398                 DEBUG_WARN(("size zero but non-null pointer\n"));
03399                 free(p->from);
03400             }
03401             p->from = p->to = NULL;
03402         }
03403     }
03404     else {
03405         // internal index reference
03406         size_t subindex  = offset >> 16;
03407         size_t suboffset = offset & 0xffff;
03408         if (subindex < subblocks->subblock_count) {
03409             if (pst_getBlockOffset(subblocks->subs[subindex].buf,
03410                                    subblocks->subs[subindex].read_size,
03411                                    subblocks->subs[subindex].i_offset,
03412                                    suboffset, &block_offset)) {
03413                 p->from = subblocks->subs[subindex].buf + block_offset.from;
03414                 p->to   = subblocks->subs[subindex].buf + block_offset.to;
03415             }
03416         }
03417     }
03418     DEBUG_RET();
03419     return (p->from) ? 0 : 1;
03420 }
03421 
03422 
03423 int pst_getBlockOffset(char *buf, size_t read_size, uint32_t i_offset, uint32_t offset, pst_block_offset *p) {
03424     uint32_t low = offset & 0xf;
03425     uint32_t of1 = offset >> 4;
03426     DEBUG_ENT("pst_getBlockOffset");
03427     if (!p || !buf || !i_offset || low || (i_offset+2+of1+sizeof(*p) > read_size)) {
03428         DEBUG_WARN(("p is NULL or buf is NULL or offset is 0 or offset has low bits or beyond read size (%p, %p, %#x, %i, %i)\n", p, buf, offset, read_size, i_offset));
03429         DEBUG_RET();
03430         return 0;
03431     }
03432     memcpy(&(p->from), &(buf[(i_offset+2)+of1]), sizeof(p->from));
03433     memcpy(&(p->to), &(buf[(i_offset+2)+of1+sizeof(p->from)]), sizeof(p->to));
03434     LE16_CPU(p->from);
03435     LE16_CPU(p->to);
03436     DEBUG_WARN(("get block offset finds from=%i(%#x), to=%i(%#x)\n", p->from, p->from, p->to, p->to));
03437     if (p->from > p->to) {
03438         DEBUG_WARN(("get block offset from > to"));
03439         DEBUG_RET();
03440         return 0;
03441     }
03442     DEBUG_RET();
03443     return 1;
03444 }
03445 
03446 
03447 pst_index_ll* pst_getID(pst_file* pf, uint64_t i_id) {
03448     pst_index_ll *ptr;
03449     DEBUG_ENT("pst_getID");
03450     if (i_id == 0) {
03451         DEBUG_RET();
03452         return NULL;
03453     }
03454 
03455     //if (i_id & 1) DEBUG_INDEX(("have odd id bit %#"PRIx64"\n", i_id));
03456     //if (i_id & 2) DEBUG_INDEX(("have two id bit %#"PRIx64"\n", i_id));
03457     i_id -= (i_id & 1);
03458 
03459     DEBUG_INDEX(("Trying to find %#"PRIx64"\n", i_id));
03460     ptr = pf->i_head;
03461     while (ptr && (ptr->i_id != i_id)) {
03462         ptr = ptr->next;
03463     }
03464     if (ptr) {DEBUG_INDEX(("Found Value %#"PRIx64"\n", i_id));            }
03465     else     {DEBUG_INDEX(("ERROR: Value %#"PRIx64" not found\n", i_id)); }
03466     DEBUG_RET();
03467     return ptr;
03468 }
03469 
03470 
03471 pst_id2_ll *pst_getID2(pst_id2_ll *head, uint64_t id2) {
03472     DEBUG_ENT("pst_getID2");
03473     DEBUG_INDEX(("looking for id2 = %#"PRIx64"\n", id2));
03474     pst_id2_ll *ptr = head;
03475     while (ptr) {
03476         if (ptr->id2 == id2) break;
03477         if (ptr->child) {
03478             pst_id2_ll *rc = pst_getID2(ptr->child, id2);
03479             if (rc) {
03480                 DEBUG_RET();
03481                 return rc;
03482             }
03483         }
03484         ptr = ptr->next;
03485     }
03486     if (ptr && ptr->id) {
03487         DEBUG_INDEX(("Found value %#"PRIx64"\n", ptr->id->i_id));
03488         DEBUG_RET();
03489         return ptr;
03490     }
03491     DEBUG_INDEX(("ERROR Not Found\n"));
03492     DEBUG_RET();
03493     return NULL;
03494 }
03495 
03496 
03505 pst_desc_ll* pst_getDptr(pst_file *pf, uint64_t d_id) {
03506     pst_desc_ll *ptr = pf->d_head;
03507     DEBUG_ENT("pst_getDptr");
03508     while (ptr && (ptr->d_id != d_id)) {
03509         //DEBUG_INDEX(("Looking for %#"PRIx64" at node %#"PRIx64" with parent %#"PRIx64"\n", id, ptr->d_id, ptr->parent_d_id));
03510         if (ptr->child) {
03511             ptr = ptr->child;
03512             continue;
03513         }
03514         while (!ptr->next && ptr->parent) {
03515             ptr = ptr->parent;
03516         }
03517         ptr = ptr->next;
03518     }
03519     DEBUG_RET();
03520     return ptr; // will be NULL or record we are looking for
03521 }
03522 
03523 
03524 void pst_printDptr(pst_file *pf, pst_desc_ll *ptr) {
03525     DEBUG_ENT("pst_printDptr");
03526     while (ptr) {
03527         DEBUG_INDEX(("%#"PRIx64" [%i] desc=%#"PRIx64", assoc tree=%#"PRIx64"\n", ptr->d_id, ptr->no_child,
03528                     (ptr->desc       ? ptr->desc->i_id       : (uint64_t)0),
03529                     (ptr->assoc_tree ? ptr->assoc_tree->i_id : (uint64_t)0)));
03530         if (ptr->child) {
03531             pst_printDptr(pf, ptr->child);
03532         }
03533         ptr = ptr->next;
03534     }
03535     DEBUG_RET();
03536 }
03537 
03538 
03539 void pst_printIDptr(pst_file* pf) {
03540     pst_index_ll *ptr = pf->i_head;
03541     DEBUG_ENT("pst_printIDptr");
03542     while (ptr) {
03543         DEBUG_INDEX(("%#"PRIx64" offset=%#"PRIx64" size=%#"PRIx64"\n", ptr->i_id, ptr->offset, ptr->size));
03544         ptr = ptr->next;
03545     }
03546     DEBUG_RET();
03547 }
03548 
03549 
03550 void pst_printID2ptr(pst_id2_ll *ptr) {
03551     DEBUG_ENT("pst_printID2ptr");
03552     while (ptr) {
03553         DEBUG_INDEX(("%#"PRIx64" id=%#"PRIx64"\n", ptr->id2, (ptr->id ? ptr->id->i_id : (uint64_t)0)));
03554         if (ptr->child) pst_printID2ptr(ptr->child);
03555         ptr = ptr->next;
03556     }
03557     DEBUG_RET();
03558 }
03559 
03560 
03570 size_t pst_read_block_size(pst_file *pf, int64_t offset, size_t size, char **buf) {
03571     size_t rsize;
03572     DEBUG_ENT("pst_read_block_size");
03573     DEBUG_READ(("Reading block from %#"PRIx64", %x bytes\n", offset, size));
03574 
03575     if (*buf) {
03576         DEBUG_READ(("Freeing old memory\n"));
03577         free(*buf);
03578     }
03579     *buf = (char*) xmalloc(size);
03580 
03581     rsize = pst_getAtPos(pf, offset, *buf, size);
03582     if (rsize != size) {
03583         DEBUG_WARN(("Didn't read all the data. fread returned less [%i instead of %i]\n", rsize, size));
03584         if (feof(pf->fp)) {
03585             DEBUG_WARN(("We tried to read past the end of the file at [offset %#"PRIx64", size %#x]\n", offset, size));
03586         } else if (ferror(pf->fp)) {
03587             DEBUG_WARN(("Error is set on file stream.\n"));
03588         } else {
03589             DEBUG_WARN(("I can't tell why it failed\n"));
03590         }
03591     }
03592 
03593     DEBUG_RET();
03594     return rsize;
03595 }
03596 
03597 
03598 int pst_decrypt(uint64_t id, char *buf, size_t size, unsigned char type) {
03599     size_t x = 0;
03600     unsigned char y;
03601     DEBUG_ENT("pst_decrypt");
03602     if (!buf) {
03603         DEBUG_RET();
03604         return -1;
03605     }
03606 
03607     if (type == PST_COMP_ENCRYPT) {
03608         x = 0;
03609         while (x < size) {
03610             y = (unsigned char)(buf[x]);
03611             buf[x] = (char)comp_enc[y]; // transpose from encrypt array
03612             x++;
03613         }
03614 
03615     } else if (type == PST_ENCRYPT) {
03616         // The following code was based on the information at
03617         // http://www.passcape.com/outlook_passwords.htm
03618         uint16_t salt = (uint16_t) (((id & 0x00000000ffff0000) >> 16) ^ (id & 0x000000000000ffff));
03619         x = 0;
03620         while (x < size) {
03621             uint8_t losalt = (salt & 0x00ff);
03622             uint8_t hisalt = (salt & 0xff00) >> 8;
03623             y = (unsigned char)buf[x];
03624             y += losalt;
03625             y = comp_high1[y];
03626             y += hisalt;
03627             y = comp_high2[y];
03628             y -= hisalt;
03629             y = comp_enc[y];
03630             y -= losalt;
03631             buf[x] = (char)y;
03632             x++;
03633             salt++;
03634         }
03635 
03636     } else {
03637         WARN(("Unknown encryption: %i. Cannot decrypt\n", type));
03638         DEBUG_RET();
03639         return -1;
03640     }
03641     DEBUG_RET();
03642     return 0;
03643 }
03644 
03645 
03646 uint64_t pst_getIntAt(pst_file *pf, char *buf) {
03647     uint64_t buf64;
03648     uint32_t buf32;
03649     if (pf->do_read64) {
03650         memcpy(&buf64, buf, sizeof(buf64));
03651         LE64_CPU(buf64);
03652         return buf64;
03653     }
03654     else {
03655         memcpy(&buf32, buf, sizeof(buf32));
03656         LE32_CPU(buf32);
03657         return buf32;
03658     }
03659 }
03660 
03661 
03662 uint64_t pst_getIntAtPos(pst_file *pf, int64_t pos ) {
03663     uint64_t buf64;
03664     uint32_t buf32;
03665     if (pf->do_read64) {
03666         (void)pst_getAtPos(pf, pos, &buf64, sizeof(buf64));
03667         LE64_CPU(buf64);
03668         return buf64;
03669     }
03670     else {
03671         (void)pst_getAtPos(pf, pos, &buf32, sizeof(buf32));
03672         LE32_CPU(buf32);
03673         return buf32;
03674     }
03675 }
03676 
03687 size_t pst_getAtPos(pst_file *pf, int64_t pos, void* buf, size_t size) {
03688     size_t rc;
03689     DEBUG_ENT("pst_getAtPos");
03690 //  pst_block_recorder **t = &pf->block_head;
03691 //  pst_block_recorder *p = pf->block_head;
03692 //  while (p && ((p->offset+p->size) <= pos)) {
03693 //      t = &p->next;
03694 //      p = p->next;
03695 //  }
03696 //  if (p && (p->offset <= pos) && (pos < (p->offset+p->size))) {
03697 //      // bump the count
03698 //      p->readcount++;
03699 //  } else {
03700 //      // add a new block
03701 //      pst_block_recorder *tail = *t;
03702 //      p = (pst_block_recorder*)xmalloc(sizeof(*p));
03703 //      *t = p;
03704 //      p->next      = tail;
03705 //      p->offset    = pos;
03706 //      p->size      = size;
03707 //      p->readcount = 1;
03708 //  }
03709 //  DEBUG_MAIN(("pst file old offset %#"PRIx64" old size %#x read count %i offset %#"PRIx64" size %#x\n",
03710 //              p->offset, p->size, p->readcount, pos, size));
03711 
03712     if (fseeko(pf->fp, pos, SEEK_SET) == -1) {
03713         DEBUG_RET();
03714         return 0;
03715     }
03716     rc = fread(buf, (size_t)1, size, pf->fp);
03717     DEBUG_RET();
03718     return rc;
03719 }
03720 
03721 
03731 size_t pst_ff_getIDblock_dec(pst_file *pf, uint64_t id, char **buf) {
03732     size_t r;
03733     int noenc = (int)(id & 2);   // disable encryption
03734     DEBUG_ENT("pst_ff_getIDblock_dec");
03735     DEBUG_INDEX(("for id %#"PRIi64"\n", id));
03736     r = pst_ff_getIDblock(pf, id, buf);
03737     if ((pf->encryption) && !(noenc)) {
03738         (void)pst_decrypt(id, *buf, r, pf->encryption);
03739     }
03740     DEBUG_HEXDUMPC(*buf, r, 16);
03741     DEBUG_RET();
03742     return r;
03743 }
03744 
03745 
03754 size_t pst_ff_getIDblock(pst_file *pf, uint64_t id, char** buf) {
03755     pst_index_ll *rec;
03756     size_t rsize;
03757     DEBUG_ENT("pst_ff_getIDblock");
03758     rec = pst_getID(pf, id);
03759     if (!rec) {
03760         DEBUG_INDEX(("Cannot find ID %#"PRIx64"\n", id));
03761         DEBUG_RET();
03762         return 0;
03763     }
03764     DEBUG_INDEX(("id = %#"PRIx64", record size = %#x, offset = %#x\n", id, rec->size, rec->offset));
03765     rsize = pst_read_block_size(pf, rec->offset, rec->size, buf);
03766     DEBUG_RET();
03767     return rsize;
03768 }
03769 
03770 
03771 size_t pst_ff_getID2block(pst_file *pf, uint64_t id2, pst_id2_ll *id2_head, char** buf) {
03772     size_t ret;
03773     pst_id2_ll* ptr;
03774     pst_holder h = {buf, NULL, 0};
03775     DEBUG_ENT("pst_ff_getID2block");
03776     ptr = pst_getID2(id2_head, id2);
03777 
03778     if (!ptr) {
03779         DEBUG_INDEX(("Cannot find id2 value %#"PRIi64"\n", id2));
03780         DEBUG_RET();
03781         return 0;
03782     }
03783     ret = pst_ff_getID2data(pf, ptr->id, &h);
03784     DEBUG_RET();
03785     return ret;
03786 }
03787 
03788 
03789 size_t pst_ff_getID2data(pst_file *pf, pst_index_ll *ptr, pst_holder *h) {
03790     size_t ret;
03791     char *b = NULL, *t;
03792     DEBUG_ENT("pst_ff_getID2data");
03793     if (!(ptr->i_id & 0x02)) {
03794         ret = pst_ff_getIDblock_dec(pf, ptr->i_id, &b);
03795         if (h->buf) {
03796             *(h->buf) = b;
03797         } else if ((h->base64 == 1) && h->fp) {
03798             t = base64_encode(b, ret);
03799             if (t) {
03800                 (void)pst_fwrite(t, (size_t)1, strlen(t), h->fp);
03801                 free(t);    // caught by valgrind
03802             }
03803             free(b);
03804         } else if (h->fp) {
03805             (void)pst_fwrite(b, (size_t)1, ret, h->fp);
03806             free(b);
03807         } else {
03808             // h-> does not specify any output
03809         }
03810 
03811     } else {
03812         // here we will assume it is a block that points to others
03813         DEBUG_READ(("Assuming it is a multi-block record because of it's id\n"));
03814         ret = pst_ff_compile_ID(pf, ptr->i_id, h, (size_t)0);
03815     }
03816     DEBUG_RET();
03817     return ret;
03818 }
03819 
03820 
03821 size_t pst_ff_compile_ID(pst_file *pf, uint64_t id, pst_holder *h, size_t size) {
03822     size_t z, a;
03823     uint16_t count, y;
03824     char *buf3 = NULL, *buf2 = NULL, *t;
03825     char *b_ptr;
03826     int  line_count = 0;
03827     char      base64_extra_chars[3];
03828     uint32_t  base64_extra = 0;
03829     pst_block_hdr  block_hdr;
03830     pst_table3_rec table3_rec;  //for type 3 (0x0101) blocks
03831 
03832     DEBUG_ENT("pst_ff_compile_ID");
03833     a = pst_ff_getIDblock(pf, id, &buf3);
03834     if (!a) {
03835         if (buf3) free(buf3);
03836         DEBUG_RET();
03837         return 0;
03838     }
03839     DEBUG_HEXDUMPC(buf3, a, 16);
03840     memcpy(&block_hdr, buf3, sizeof(block_hdr));
03841     LE16_CPU(block_hdr.index_offset);
03842     LE16_CPU(block_hdr.type);
03843     LE32_CPU(block_hdr.offset);
03844     DEBUG_EMAIL(("block header (index_offset=%#hx, type=%#hx, offset=%#x)\n", block_hdr.index_offset, block_hdr.type, block_hdr.offset));
03845 
03846     if (block_hdr.index_offset != (uint16_t)0x0101) { //type 3
03847         DEBUG_WARN(("WARNING: not a type 0x0101 buffer, Treating as normal buffer\n"));
03848         if (pf->encryption) (void)pst_decrypt(id, buf3, a, pf->encryption);
03849         if (h->buf)
03850             *(h->buf) = buf3;
03851         else if (h->base64 == 1 && h->fp) {
03852             t = base64_encode(buf3, a);
03853             if (t) {
03854                 (void)pst_fwrite(t, (size_t)1, strlen(t), h->fp);
03855                 free(t);    // caught by valgrind
03856             }
03857             free(buf3);
03858         } else if (h->fp) {
03859             (void)pst_fwrite(buf3, (size_t)1, a, h->fp);
03860             free(buf3);
03861         } else {
03862             // h-> does not specify any output
03863         }
03864         DEBUG_RET();
03865         return a;
03866     }
03867     count = block_hdr.type;
03868     b_ptr = buf3 + 8;
03869     line_count = 0;
03870     for (y=0; y<count; y++) {
03871         b_ptr += pst_decode_type3(pf, &table3_rec, b_ptr);
03872         z = pst_ff_getIDblock_dec(pf, table3_rec.id, &buf2);
03873         if (!z) {
03874             DEBUG_WARN(("call to getIDblock returned zero %i\n", z));
03875             if (buf2) free(buf2);
03876             free(buf3);
03877             DEBUG_RET();
03878             return z;
03879         }
03880         if (h->buf) {
03881             *(h->buf) = realloc(*(h->buf), size+z+1);
03882             DEBUG_READ(("appending read data of size %i onto main buffer from pos %i\n", z, size));
03883             memcpy(&((*(h->buf))[size]), buf2, z);
03884         } else if ((h->base64 == 1) && h->fp) {
03885             if (base64_extra) {
03886                 // include any bytes left over from the last encoding
03887                 buf2 = (char*)realloc(buf2, z+base64_extra);
03888                 memmove(buf2+base64_extra, buf2, z);
03889                 memcpy(buf2, base64_extra_chars, base64_extra);
03890                 z += base64_extra;
03891             }
03892 
03893             // find out how many bytes will be left over after this encoding and save them
03894             base64_extra = z % 3;
03895             if (base64_extra) {
03896                 z -= base64_extra;
03897                 memcpy(base64_extra_chars, buf2+z, base64_extra);
03898             }
03899 
03900             // encode this chunk
03901             t = base64_encode_multiple(buf2, z, &line_count);
03902             if (t) {
03903                 DEBUG_READ(("writing %i bytes to file as base64 [%i]. Currently %i\n", z, strlen(t), size));
03904                 (void)pst_fwrite(t, (size_t)1, strlen(t), h->fp);
03905                 free(t);    // caught by valgrind
03906             }
03907         } else if (h->fp) {
03908             DEBUG_READ(("writing %i bytes to file. Currently %i\n", z, size));
03909             (void)pst_fwrite(buf2, (size_t)1, z, h->fp);
03910         } else {
03911             // h-> does not specify any output
03912         }
03913         size += z;
03914     }
03915     if ((h->base64 == 1) && h->fp && base64_extra) {
03916         // need to encode any bytes left over
03917         t = base64_encode_multiple(base64_extra_chars, (size_t)base64_extra, &line_count);
03918         if (t) {
03919             (void)pst_fwrite(t, (size_t)1, strlen(t), h->fp);
03920             free(t);    // caught by valgrind
03921         }
03922     }
03923     free(buf3);
03924     if (buf2) free(buf2);
03925     DEBUG_RET();
03926     return size;
03927 }
03928 
03929 
03930 #ifdef _WIN32
03931 char * fileTimeToAscii(const FILETIME* filetime) {
03932     time_t t;
03933     DEBUG_ENT("fileTimeToAscii");
03934     t = fileTimeToUnixTime(filetime, 0);
03935     if (t == -1)
03936         DEBUG_WARN(("ERROR time_t varible that was produced, is -1\n"));
03937     DEBUG_RET();
03938     return ctime(&t);
03939 }
03940 
03941 
03942 time_t fileTimeToUnixTime(const FILETIME* filetime, DWORD *x) {
03943     SYSTEMTIME s;
03944     struct tm t;
03945     DEBUG_ENT("fileTimeToUnixTime");
03946     memset (&t, 0, sizeof(struct tm));
03947     FileTimeToSystemTime(filetime, &s);
03948     t.tm_year = s.wYear-1900; // this is what is required
03949     t.tm_mon = s.wMonth-1; // also required! It made me a bit confused
03950     t.tm_mday = s.wDay;
03951     t.tm_hour = s.wHour;
03952     t.tm_min = s.wMinute;
03953     t.tm_sec = s.wSecond;
03954     DEBUG_RET();
03955     return mktime(&t);
03956 }
03957 
03958 
03959 struct tm * fileTimeToStructTM (const FILETIME *filetime) {
03960     time_t t1;
03961     t1 = fileTimeToUnixTime(filetime, 0);
03962     return gmtime(&t1);
03963 }
03964 
03965 
03966 #endif //_WIN32
03967 
03968 int pst_stricmp(char *a, char *b) {
03969     // compare strings case-insensitive.
03970     // returns -1 if a < b, 0 if a==b, 1 if a > b
03971     while(*a != '\0' && *b != '\0' && toupper(*a)==toupper(*b)) {
03972         a++; b++;
03973     }
03974     if (toupper(*a) == toupper(*b))
03975         return 0;
03976     else if (toupper(*a) < toupper(*b))
03977         return -1;
03978     else
03979         return 1;
03980 }
03981 
03982 
03983 int pst_strincmp(char *a, char *b, size_t x) {
03984     // compare upto x chars in string a and b case-insensitively
03985     // returns -1 if a < b, 0 if a==b, 1 if a > b
03986     size_t y = 0;
03987     while (*a != '\0' && *b != '\0' && y < x && toupper(*a)==toupper(*b)) {
03988         a++; b++; y++;
03989     }
03990     // if we have reached the end of either string, or a and b still match
03991     if (*a == '\0' || *b == '\0' || toupper(*a)==toupper(*b))
03992         return 0;
03993     else if (toupper(*a) < toupper(*b))
03994         return -1;
03995     else
03996         return 1;
03997 }
03998 
03999 
04000 size_t pst_fwrite(const void* ptr, size_t size, size_t nmemb, FILE *stream) {
04001     size_t r;
04002     DEBUG_ENT("pst_fwrite");
04003     if (ptr)
04004         r = fwrite(ptr, size, nmemb, stream);
04005     else {
04006         r = 0;
04007         DEBUG_WARN(("An attempt to write a NULL Pointer was made\n"));
04008     }
04009     DEBUG_RET();
04010     return r;
04011 }
04012 
04013 
04014 char * pst_wide_to_single(char *wt, size_t size) {
04015     // returns the first byte of each wide char. the size is the number of bytes in source
04016     char *x, *y;
04017     DEBUG_ENT("pst_wide_to_single");
04018     x = xmalloc((size/2)+1);
04019     y = x;
04020     while (size != 0 && *wt != '\0') {
04021         *y = *wt;
04022         wt+=2;
04023         size -= 2;
04024         y++;
04025     }
04026     *y = '\0';
04027     DEBUG_RET();
04028     return x;
04029 }
04030 
04031 
04032 char *pst_rfc2426_escape(char *str) {
04033     static char*  buf    = NULL;
04034     static size_t buflen = 0;
04035     char *ret, *a, *b;
04036     size_t x = 0;
04037     int y, z;
04038     DEBUG_ENT("rfc2426_escape");
04039     if (!str)
04040         ret = str;
04041     else {
04042 
04043         // calculate space required to escape all the following characters
04044         y = pst_chr_count(str, ',')
04045           + pst_chr_count(str, '\\')
04046           + pst_chr_count(str, ';')
04047           + pst_chr_count(str, '\n');
04048         z = pst_chr_count(str, '\r');
04049         if (y == 0 && z == 0)
04050             // there isn't any extra space required
04051             ret = str;
04052         else {
04053             x = strlen(str) + y - z + 1; // don't forget room for the NUL
04054             if (x > buflen) {
04055                 buf = (char*) realloc(buf, x);
04056                 buflen = x;
04057             }
04058             a = str;
04059             b = buf;
04060             while (*a != '\0') {
04061                 switch (*a) {
04062                 case ',' :
04063                 case '\\':
04064                 case ';' :
04065                     *(b++) = '\\';
04066                     *b = *a;
04067                     break;
04068                 case '\n':  // newlines are encoded as "\n"
04069                     *(b++) = '\\';
04070                     *b = 'n';
04071                     break;
04072                 case '\r':  // skip cr
04073                     b--;
04074                     break;
04075                 default:
04076                     *b=*a;
04077                 }
04078                 b++;
04079                 a++;
04080             }
04081             *b = '\0'; // NUL-terminate the string (buf)
04082             ret = buf;
04083         }
04084     }
04085     DEBUG_RET();
04086     return ret;
04087 }
04088 
04089 
04090 int pst_chr_count(char *str, char x) {
04091     int r = 0;
04092     while (*str) {
04093         if (*str == x) r++;
04094         str++;
04095     }
04096     return r;
04097 }
04098 
04099 
04100 char *pst_rfc2425_datetime_format(FILETIME *ft) {
04101     static char buffer[30];
04102     struct tm *stm = NULL;
04103     DEBUG_ENT("rfc2425_datetime_format");
04104     stm = fileTimeToStructTM(ft);
04105     if (strftime(buffer, sizeof(buffer), "%Y-%m-%dT%H:%M:%SZ", stm)==0) {
04106         DEBUG_INFO(("Problem occured formatting date\n"));
04107     }
04108     DEBUG_RET();
04109     return buffer;
04110 }
04111 
04112 
04113 char *pst_rfc2445_datetime_format(FILETIME *ft) {
04114     static char buffer[30];
04115     struct tm *stm = NULL;
04116     DEBUG_ENT("rfc2445_datetime_format");
04117     stm = fileTimeToStructTM(ft);
04118     if (strftime(buffer, sizeof(buffer), "%Y%m%dT%H%M%SZ", stm)==0) {
04119         DEBUG_INFO(("Problem occured formatting date\n"));
04120     }
04121     DEBUG_RET();
04122     return buffer;
04123 }
04124 
04125 
04132 const char* codepage(int cp) {
04133     static char buffer[20];
04134     switch (cp) {
04135         case   932 : return "iso-2022-jp";
04136         case   936 : return "gb2313";
04137         case   950 : return "big5";
04138         case 20127 : return "us-ascii";
04139         case 20269 : return "iso-6937";
04140         case 20865 : return "iso-8859-15";
04141         case 20866 : return "koi8-r";
04142         case 21866 : return "koi8-u";
04143         case 28591 : return "iso-8859-1";
04144         case 28592 : return "iso-8859-2";
04145         case 28595 : return "iso-8859-5";
04146         case 28596 : return "iso-8859-6";
04147         case 28597 : return "iso-8859-7";
04148         case 28598 : return "iso-8859-8";
04149         case 28599 : return "iso-8859-9";
04150         case 28600 : return "iso-8859-10";
04151         case 28601 : return "iso-8859-11";
04152         case 28602 : return "iso-8859-12";
04153         case 28603 : return "iso-8859-13";
04154         case 28604 : return "iso-8859-14";
04155         case 28605 : return "iso-8859-15";
04156         case 28606 : return "iso-8859-16";
04157         case 50220 : return "iso-2022-jp";
04158         case 50221 : return "csiso2022jp";
04159         case 51932 : return "euc-jp";
04160         case 51949 : return "euc-kr";
04161         case 65000 : return "utf-7";
04162         case 65001 : return "utf-8";
04163         default :
04164             snprintf(buffer, sizeof(buffer), "windows-%d", cp);
04165             return buffer;
04166     }
04167     return NULL;
04168 }
04169 
04170 
04175 const char*    pst_default_charset(pst_item *item)
04176 {
04177     return (item->body_charset.str) ? item->body_charset.str :
04178            (item->message_codepage) ? codepage(item->message_codepage) :
04179            (item->internet_cpid)    ? codepage(item->internet_cpid) :
04180            "utf-8";
04181 }
04182 
04183 
04189 void pst_convert_utf8_null(pst_item *item, pst_string *str)
04190 {
04191     if (!str->str) return;
04192     pst_convert_utf8(item, str);
04193 }
04194 
04195 
04201 void pst_convert_utf8(pst_item *item, pst_string *str)
04202 {
04203     if (str->is_utf8) return;
04204     if (!str->str) {
04205         str->str = strdup("");
04206         return;
04207     }
04208     const char *charset = pst_default_charset(item);
04209     if (!strcasecmp("utf-8", charset)) return;  // already utf8
04210     DEBUG_ENT("pst_convert_utf8");
04211     vbuf *newer = vballoc(2);
04212     size_t rc = vb_8bit2utf8(newer, str->str, strlen(str->str) + 1, charset);
04213     if (rc == (size_t)-1) {
04214         free(newer->b);
04215         DEBUG_EMAIL(("Failed to convert %s to utf-8 - %s\n", charset, str->str));
04216     }
04217     else {
04218         free(str->str);
04219         str->str = newer->b;
04220         str->is_utf8 = 1;
04221     }
04222     free(newer);
04223     DEBUG_RET();
04224 }

Generated on Thu Mar 19 16:39:26 2009 for 'LibPst' by  doxygen 1.3.9.1