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

Generated on Fri Apr 17 12:59:05 2009 for 'LibPst' by  doxygen 1.3.9.1