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

Generated on 24 Dec 2011 for 'LibPst' by  doxygen 1.6.1