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 
02127 static int pst_process(uint64_t block_id, pst_mapi_object *list, pst_item *item, pst_item_attach *attach) {
02128     DEBUG_ENT("pst_process");
02129     if (!item) {
02130         DEBUG_WARN(("item cannot be NULL.\n"));
02131         DEBUG_RET();
02132         return -1;
02133     }
02134 
02135     item->block_id = block_id;
02136     while (list) {
02137         int32_t x;
02138         char time_buffer[30];
02139         for (x=0; x<list->count_elements; x++) {
02140             int32_t t;
02141             uint32_t ut;
02142             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));
02143 
02144             switch (list->elements[x]->mapi_id) {
02145                 case PST_ATTRIB_HEADER: // CUSTOM attribute for saying the Extra Headers
02146                     if (list->elements[x]->extra) {
02147                         if (list->elements[x]->type == 0x0101e) {
02148                             // an array of strings, rather than a single string
02149                             int32_t string_length, i, offset, next_offset;
02150                             int32_t p = 0;
02151                             int32_t array_element_count = PST_LE_GET_INT32(list->elements[x]->data); p+=4;
02152                             for (i = 1; i <= array_element_count; i++) {
02153                                 pst_item_extra_field *ef = (pst_item_extra_field*) pst_malloc(sizeof(pst_item_extra_field));
02154                                 memset(ef, 0, sizeof(pst_item_extra_field));
02155                                 offset      = PST_LE_GET_INT32(list->elements[x]->data + p); p+=4;
02156                                 next_offset = (i == array_element_count) ? list->elements[x]->size : PST_LE_GET_INT32(list->elements[x]->data + p);;
02157                                 string_length = next_offset - offset;
02158                                 ef->value = pst_malloc(string_length + 1);
02159                                 memcpy(ef->value, list->elements[x]->data + offset, string_length);
02160                                 ef->value[string_length] = '\0';
02161                                 ef->field_name = strdup(list->elements[x]->extra);
02162                                 ef->next       = item->extra_fields;
02163                                 item->extra_fields = ef;
02164                                 DEBUG_INFO(("Extra Field - \"%s\" = \"%s\"\n", ef->field_name, ef->value));
02165                             }
02166                         }
02167                         else {
02168                             // should be a single string
02169                             pst_item_extra_field *ef = (pst_item_extra_field*) pst_malloc(sizeof(pst_item_extra_field));
02170                             memset(ef, 0, sizeof(pst_item_extra_field));
02171                             LIST_COPY_CSTR(ef->value);
02172                             if (ef->value) {
02173                                 ef->field_name = strdup(list->elements[x]->extra);
02174                                 ef->next       = item->extra_fields;
02175                                 item->extra_fields = ef;
02176                                 DEBUG_INFO(("Extra Field - \"%s\" = \"%s\"\n", ef->field_name, ef->value));
02177                                 if (strcmp(ef->field_name, "content-type") == 0) {
02178                                     char *p = strstr(ef->value, "charset=\"");
02179                                     if (p) {
02180                                         p += 9; // skip over charset="
02181                                         char *pp = strchr(p, '"');
02182                                         if (pp) {
02183                                             *pp = '\0';
02184                                             char *set = strdup(p);
02185                                             *pp = '"';
02186                                             if (item->body_charset.str) free(item->body_charset.str);
02187                                             item->body_charset.str     = set;
02188                                             item->body_charset.is_utf8 = 1;
02189                                             DEBUG_INFO(("body charset %s from content-type extra field\n", set));
02190                                         }
02191                                     }
02192                                 }
02193                             }
02194                             else {
02195                                 DEBUG_WARN(("What does this mean? Internet header %s value\n", list->elements[x]->extra));
02196                                 DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02197                                 free(ef);   // caught by valgrind
02198                             }
02199                         }
02200                     }
02201                     break;
02202                 case 0x0002: // PR_ALTERNATE_RECIPIENT_ALLOWED
02203                     if (list->elements[x]->type == 0x0b) {
02204                         // If set to true, the sender allows this email to be autoforwarded
02205                         LIST_COPY_EMAIL_BOOL("AutoForward allowed", item->email->autoforward);
02206                         if (!item->email->autoforward) item->email->autoforward = -1;
02207                     } else {
02208                         DEBUG_WARN(("What does this mean?\n"));
02209                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02210                     }
02211                     break;
02212                 case 0x0003: // Extended Attributes table
02213                     DEBUG_INFO(("Extended Attributes Table - NOT PROCESSED\n"));
02214                     break;
02215                 case 0x0017: // PR_IMPORTANCE - How important the sender deems it to be
02216                     LIST_COPY_EMAIL_ENUM("Importance Level", item->email->importance, 0, 3, "Low", "Normal", "High");
02217                     break;
02218                 case 0x001A: // PR_MESSAGE_CLASS IPM.x
02219                     if ((list->elements[x]->type == 0x1e) ||
02220                         (list->elements[x]->type == 0x1f)) {
02221                         LIST_COPY_CSTR(item->ascii_type);
02222                         if (!item->ascii_type) item->ascii_type = strdup("unknown");
02223                         if (pst_strincmp("IPM.Note", item->ascii_type, 8) == 0)
02224                             item->type = PST_TYPE_NOTE;
02225                         else if (pst_stricmp("IPM", item->ascii_type) == 0)
02226                             item->type = PST_TYPE_NOTE;
02227                         else if (pst_strincmp("IPM.Contact", item->ascii_type, 11) == 0)
02228                             item->type = PST_TYPE_CONTACT;
02229                         else if (pst_strincmp("REPORT.IPM.Note", item->ascii_type, 15) == 0)
02230                             item->type = PST_TYPE_REPORT;
02231                         else if (pst_strincmp("IPM.Activity", item->ascii_type, 12) == 0)
02232                             item->type = PST_TYPE_JOURNAL;
02233                         else if (pst_strincmp("IPM.Appointment", item->ascii_type, 15) == 0)
02234                             item->type = PST_TYPE_APPOINTMENT;
02235                         else if (pst_strincmp("IPM.Schedule.Meeting", item->ascii_type, 20) == 0)
02236                             item->type = PST_TYPE_SCHEDULE;     // meeting requests and responses transported over email
02237                         else if (pst_strincmp("IPM.StickyNote", item->ascii_type, 14) == 0)
02238                             item->type = PST_TYPE_STICKYNOTE;
02239                         else if (pst_strincmp("IPM.Task", item->ascii_type, 8) == 0)
02240                             item->type = PST_TYPE_TASK;
02241                         else
02242                             item->type = PST_TYPE_OTHER;
02243                         DEBUG_INFO(("Message class %s [%"PRIi32"] \n", item->ascii_type, item->type));
02244                     }
02245                     else {
02246                         DEBUG_WARN(("What does this mean?\n"));
02247                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02248                     }
02249                     break;
02250                 case 0x0023: // PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED
02251                     if (list->elements[x]->type == 0x0b) {
02252                         // set if the sender wants a delivery report from all recipients
02253                         LIST_COPY_EMAIL_BOOL("Global Delivery Report", item->email->delivery_report);
02254                     }
02255                     else {
02256                         DEBUG_WARN(("What does this mean?\n"));
02257                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02258                     }
02259                     break;
02260                 case 0x0026: // PR_PRIORITY
02261                     LIST_COPY_EMAIL_ENUM("Priority", item->email->priority, 1, 3, "NonUrgent", "Normal", "Urgent");
02262                     break;
02263                 case 0x0029: // PR_READ_RECEIPT_REQUESTED
02264                     LIST_COPY_EMAIL_BOOL("Read Receipt", item->email->read_receipt);
02265                     break;
02266                 case 0x002B: // PR_RECIPIENT_REASSIGNMENT_PROHIBITED
02267                     LIST_COPY_BOOL("Reassignment Prohibited (Private)", item->private_member);
02268                     break;
02269                 case 0x002E: // PR_ORIGINAL_SENSITIVITY - the sensitivity of the message before being replied to or forwarded
02270                     LIST_COPY_EMAIL_ENUM("Original Sensitivity", item->email->original_sensitivity, 0, 4,
02271                         "None", "Personal", "Private", "Company Confidential");
02272                     break;
02273                 case 0x0032: // PR_REPORT_TIME
02274                     LIST_COPY_EMAIL_TIME("Report time", item->email->report_time);
02275                     break;
02276                 case 0x0036: // PR_SENSITIVITY - sender's opinion of the sensitivity of an email
02277                     LIST_COPY_EMAIL_ENUM("Sensitivity", item->email->sensitivity, 0, 4,
02278                         "None", "Personal", "Private", "Company Confidential");
02279                     break;
02280                 case 0x0037: // PR_SUBJECT raw subject
02281                     {
02282                         int off = 0;
02283                         if ((list->elements[x]->size > 2) && (((uint8_t)list->elements[x]->data[0]) < 0x20)) {
02284                             off = 2;
02285                         }
02286                         list->elements[x]->data += off;
02287                         list->elements[x]->size -= off;
02288                         LIST_COPY_STR("Raw Subject", item->subject);
02289                         list->elements[x]->size += off;
02290                         list->elements[x]->data -= off;
02291                     }
02292                     break;
02293                 case 0x0039: // PR_CLIENT_SUBMIT_TIME Date Email Sent/Created
02294                     LIST_COPY_EMAIL_TIME("Date sent", item->email->sent_date);
02295                     break;
02296                 case 0x003B: // PR_SENT_REPRESENTING_SEARCH_KEY Sender address 1
02297                     LIST_COPY_EMAIL_STR("Sent on behalf of address 1", item->email->outlook_sender);
02298                     break;
02299                 case 0x003F: // PR_RECEIVED_BY_ENTRYID Structure containing Recipient
02300                     DEBUG_INFO(("Recipient Structure 1 -- NOT PROCESSED\n"));
02301                     break;
02302                 case 0x0040: // PR_RECEIVED_BY_NAME Name of Recipient Structure
02303                     LIST_COPY_EMAIL_STR("Received By Name 1", item->email->outlook_received_name1);
02304                     break;
02305                 case 0x0041: // PR_SENT_REPRESENTING_ENTRYID Structure containing Sender
02306                     DEBUG_INFO(("Sent on behalf of Structure 1 -- NOT PROCESSED\n"));
02307                     break;
02308                 case 0x0042: // PR_SENT_REPRESENTING_NAME
02309                     LIST_COPY_EMAIL_STR("Sent on behalf of", item->email->outlook_sender_name);
02310                     break;
02311                 case 0x0043: // PR_RCVD_REPRESENTING_ENTRYID Recipient Structure 2
02312                     DEBUG_INFO(("Received on behalf of Structure -- NOT PROCESSED\n"));
02313                     break;
02314                 case 0x0044: // PR_RCVD_REPRESENTING_NAME
02315                     LIST_COPY_EMAIL_STR("Received on behalf of", item->email->outlook_recipient_name);
02316                     break;
02317                 case 0x004F: // PR_REPLY_RECIPIENT_ENTRIES Reply-To Structure
02318                     DEBUG_INFO(("Reply-To Structure -- NOT PROCESSED\n"));
02319                     break;
02320                 case 0x0050: // PR_REPLY_RECIPIENT_NAMES Name of Reply-To Structure
02321                     LIST_COPY_EMAIL_STR("Reply-To", item->email->reply_to);
02322                     break;
02323                 case 0x0051: // PR_RECEIVED_BY_SEARCH_KEY Recipient Address 1
02324                     LIST_COPY_EMAIL_STR("Recipient's Address 1", item->email->outlook_recipient);
02325                     break;
02326                 case 0x0052: // PR_RCVD_REPRESENTING_SEARCH_KEY Recipient Address 2
02327                     LIST_COPY_EMAIL_STR("Recipient's Address 2", item->email->outlook_recipient2);
02328                     break;
02329                 case 0x0057: // PR_MESSAGE_TO_ME
02330                     // this user is listed explicitly in the TO address
02331                     LIST_COPY_EMAIL_BOOL("My address in TO field", item->email->message_to_me);
02332                     break;
02333                 case 0x0058: // PR_MESSAGE_CC_ME
02334                     // this user is listed explicitly in the CC address
02335                     LIST_COPY_EMAIL_BOOL("My address in CC field", item->email->message_cc_me);
02336                     break;
02337                 case 0x0059: // PR_MESSAGE_RECIP_ME
02338                     // this user appears in TO, CC or BCC address list
02339                     LIST_COPY_EMAIL_BOOL("Message addressed to me", item->email->message_recip_me);
02340                     break;
02341                 case 0x0063: // PR_RESPONSE_REQUESTED
02342                     LIST_COPY_BOOL("Response requested", item->response_requested);
02343                     break;
02344                 case 0x0064: // PR_SENT_REPRESENTING_ADDRTYPE Access method for Sender Address
02345                     LIST_COPY_EMAIL_STR("Sent on behalf of address type", item->email->sender_access);
02346                     break;
02347                 case 0x0065: // PR_SENT_REPRESENTING_EMAIL_ADDRESS Sender Address
02348                     LIST_COPY_EMAIL_STR("Sent on behalf of address", item->email->sender_address);
02349                     break;
02350                 case 0x0070: // PR_CONVERSATION_TOPIC Processed Subject
02351                     LIST_COPY_EMAIL_STR("Processed Subject (Conversation Topic)", item->email->processed_subject);
02352                     break;
02353                 case 0x0071: // PR_CONVERSATION_INDEX
02354                     LIST_COPY_EMAIL_BIN("Conversation Index", item->email->conversation_index);
02355                     break;
02356                 case 0x0072: // PR_ORIGINAL_DISPLAY_BCC
02357                     LIST_COPY_EMAIL_STR("Original display bcc", item->email->original_bcc);
02358                     break;
02359                 case 0x0073: // PR_ORIGINAL_DISPLAY_CC
02360                     LIST_COPY_EMAIL_STR("Original display cc", item->email->original_cc);
02361                     break;
02362                 case 0x0074: // PR_ORIGINAL_DISPLAY_TO
02363                     LIST_COPY_EMAIL_STR("Original display to", item->email->original_to);
02364                     break;
02365                 case 0x0075: // PR_RECEIVED_BY_ADDRTYPE Recipient Access Method
02366                     LIST_COPY_EMAIL_STR("Received by Address type", item->email->recip_access);
02367                     break;
02368                 case 0x0076: // PR_RECEIVED_BY_EMAIL_ADDRESS Recipient Address
02369                     LIST_COPY_EMAIL_STR("Received by Address", item->email->recip_address);
02370                     break;
02371                 case 0x0077: // PR_RCVD_REPRESENTING_ADDRTYPE Recipient Access Method 2
02372                     LIST_COPY_EMAIL_STR("Received on behalf of Address type", item->email->recip2_access);
02373                     break;
02374                 case 0x0078: // PR_RCVD_REPRESENTING_EMAIL_ADDRESS Recipient Address 2
02375                     LIST_COPY_EMAIL_STR("Received on behalf of Address", item->email->recip2_address);
02376                     break;
02377                 case 0x007D: // PR_TRANSPORT_MESSAGE_HEADERS Internet Header
02378                     LIST_COPY_EMAIL_STR("Internet Header", item->email->header);
02379                     break;
02380                 case 0x0C04: // PR_NDR_REASON_CODE
02381                     LIST_COPY_EMAIL_INT32("NDR reason code", item->email->ndr_reason_code);
02382                     break;
02383                 case 0x0C05: // PR_NDR_DIAG_CODE
02384                     LIST_COPY_EMAIL_INT32("NDR diag code", item->email->ndr_diag_code);
02385                     break;
02386                 case 0x0C06: // PR_NON_RECEIPT_NOTIFICATION_REQUESTED
02387                     DEBUG_INFO(("Non-Receipt Notification Requested -- NOT PROCESSED\n"));
02388                     break;
02389                 case 0x0C17: // PR_REPLY_REQUESTED
02390                     LIST_COPY_EMAIL_BOOL("Reply Requested", item->email->reply_requested);
02391                     break;
02392                 case 0x0C19: // PR_SENDER_ENTRYID Sender Structure 2
02393                     DEBUG_INFO(("Sender Structure 2 -- NOT PROCESSED\n"));
02394                     break;
02395                 case 0x0C1A: // PR_SENDER_NAME Name of Sender Structure 2
02396                     LIST_COPY_EMAIL_STR("Name of Sender Structure 2", item->email->outlook_sender_name2);
02397                     break;
02398                 case 0x0C1B: // PR_SUPPLEMENTARY_INFO
02399                     LIST_COPY_EMAIL_STR("Supplementary info", item->email->supplementary_info);
02400                     break;
02401                 case 0x0C1D: // PR_SENDER_SEARCH_KEY Name of Sender Address 2
02402                     LIST_COPY_EMAIL_STR("Name of Sender Address 2 (Sender search key)", item->email->outlook_sender2);
02403                     break;
02404                 case 0x0C1E: // PR_SENDER_ADDRTYPE Sender Address 2 access method
02405                     LIST_COPY_EMAIL_STR("Sender Address type", item->email->sender2_access);
02406                     break;
02407                 case 0x0C1F: // PR_SENDER_EMAIL_ADDRESS Sender Address 2
02408                     LIST_COPY_EMAIL_STR("Sender Address", item->email->sender2_address);
02409                     break;
02410                 case 0x0C20: // PR_NDR_STATUS_CODE
02411                     LIST_COPY_EMAIL_INT32("NDR status code", item->email->ndr_status_code);
02412                     break;
02413                 case 0x0E01: // PR_DELETE_AFTER_SUBMIT
02414                     LIST_COPY_EMAIL_BOOL("Delete after submit", item->email->delete_after_submit);
02415                     break;
02416                 case 0x0E02: // PR_DISPLAY_BCC BCC Addresses
02417                     LIST_COPY_EMAIL_STR("Display BCC Addresses", item->email->bcc_address);
02418                     break;
02419                 case 0x0E03: // PR_DISPLAY_CC CC Addresses
02420                     LIST_COPY_EMAIL_STR("Display CC Addresses", item->email->cc_address);
02421                     break;
02422                 case 0x0E04: // PR_DISPLAY_TO Address Sent-To
02423                     LIST_COPY_EMAIL_STR("Display Sent-To Address", item->email->sentto_address);
02424                     break;
02425                 case 0x0E06: // PR_MESSAGE_DELIVERY_TIME Date 3 - Email Arrival Date
02426                     LIST_COPY_EMAIL_TIME("Date 3 (Delivery Time)", item->email->arrival_date);
02427                     break;
02428                 case 0x0E07: // PR_MESSAGE_FLAGS Email Flag
02429                     LIST_COPY_EMAIL_INT32("Message Flags", item->flags);
02430                     break;
02431                 case 0x0E08: // PR_MESSAGE_SIZE Total size of a message object
02432                     LIST_COPY_INT32("Message Size", item->message_size);
02433                     break;
02434                 case 0x0E0A: // PR_SENTMAIL_ENTRYID
02435                     // folder that this message is sent to after submission
02436                     LIST_COPY_EMAIL_ENTRYID("Sentmail EntryID", item->email->sentmail_folder);
02437                     break;
02438                 case 0x0E1D: // PR_NORMALIZED_SUBJECT
02439                     LIST_COPY_EMAIL_STR("Normalized subject", item->email->outlook_normalized_subject);
02440                     break;
02441                 case 0x0E1F: // PR_RTF_IN_SYNC
02442                     // True means that the rtf version is same as text body
02443                     // False means rtf version is more up-to-date than text body
02444                     // if this value doesn't exist, text body is more up-to-date than rtf and
02445                     // cannot update to the rtf
02446                     LIST_COPY_EMAIL_BOOL("Compressed RTF in Sync", item->email->rtf_in_sync);
02447                     break;
02448                 case 0x0E20: // PR_ATTACH_SIZE binary Attachment data in record
02449                     NULL_CHECK(attach);
02450                     LIST_COPY_INT32("Attachment Size", t);
02451                     // ignore this. we either get data and size from 0x3701
02452                     // or id codes from 0x3701 or 0x67f2
02453                     break;
02454                 case 0x0FF9: // PR_RECORD_KEY Record Header 1
02455                     LIST_COPY_BIN(item->record_key);
02456                     DEBUG_INFO(("Record Key\n"));
02457                     DEBUG_HEXDUMP(item->record_key.data, item->record_key.size);
02458                     break;
02459                 case 0x1000: // PR_BODY
02460                     LIST_COPY_STR("Plain Text body", item->body);
02461                     break;
02462                 case 0x1001: // PR_REPORT_TEXT
02463                     LIST_COPY_EMAIL_STR("Report Text", item->email->report_text);
02464                     break;
02465                 case 0x1006: // PR_RTF_SYNC_BODY_CRC
02466                     LIST_COPY_EMAIL_INT32("RTF Sync Body CRC", item->email->rtf_body_crc);
02467                     break;
02468                 case 0x1007: // PR_RTF_SYNC_BODY_COUNT
02469                     // a count of the *significant* charcters in the rtf body. Doesn't count
02470                     // whitespace and other ignorable characters
02471                     LIST_COPY_EMAIL_INT32("RTF Sync Body character count", item->email->rtf_body_char_count);
02472                     break;
02473                 case 0x1008: // PR_RTF_SYNC_BODY_TAG
02474                     // the first couple of lines of RTF body so that after modification, then beginning can
02475                     // once again be found
02476                     LIST_COPY_EMAIL_STR("RTF Sync body tag", item->email->rtf_body_tag);
02477                     break;
02478                 case 0x1009: // PR_RTF_COMPRESSED - rtf data is lzw compressed
02479                     LIST_COPY_EMAIL_BIN("RTF Compressed body", item->email->rtf_compressed);
02480                     break;
02481                 case 0x1010: // PR_RTF_SYNC_PREFIX_COUNT
02482                     // a count of the ignored characters before the first significant character
02483                     LIST_COPY_EMAIL_INT32("RTF whitespace prefix count", item->email->rtf_ws_prefix_count);
02484                     break;
02485                 case 0x1011: // PR_RTF_SYNC_TRAILING_COUNT
02486                     // a count of the ignored characters after the last significant character
02487                     LIST_COPY_EMAIL_INT32("RTF whitespace tailing count", item->email->rtf_ws_trailing_count);
02488                     break;
02489                 case 0x1013: // HTML body
02490                     LIST_COPY_EMAIL_STR("HTML body", item->email->htmlbody);
02491                     break;
02492                 case 0x1035: // Message ID
02493                     LIST_COPY_EMAIL_STR("Message ID", item->email->messageid);
02494                     break;
02495                 case 0x1042: // in-reply-to
02496                     LIST_COPY_EMAIL_STR("In-Reply-To", item->email->in_reply_to);
02497                     break;
02498                 case 0x1046: // Return Path - this seems to be the message-id of the rfc822 mail that is being returned
02499                     LIST_COPY_EMAIL_STR("Return Path", item->email->return_path_address);
02500                     break;
02501                 case 0x3001: // PR_DISPLAY_NAME File As
02502                     LIST_COPY_STR("Display Name", item->file_as);
02503                     break;
02504                 case 0x3002: // PR_ADDRTYPE
02505                     LIST_COPY_CONTACT_STR("Address Type", item->contact->address1_transport);
02506                     break;
02507                 case 0x3003: // PR_EMAIL_ADDRESS
02508                     LIST_COPY_CONTACT_STR("Contact email Address", item->contact->address1);
02509                     break;
02510                 case 0x3004: // PR_COMMENT Comment for item - usually folders
02511                     LIST_COPY_STR("Comment", item->comment);
02512                     break;
02513                 case 0x3007: // PR_CREATION_TIME Date 4 - Creation Date?
02514                     LIST_COPY_TIME("Date 4 (Item Creation Date)", item->create_date);
02515                     break;
02516                 case 0x3008: // PR_LAST_MODIFICATION_TIME Date 5 - Modify Date
02517                     LIST_COPY_TIME("Date 5 (Modify Date)", item->modify_date);
02518                     break;
02519                 case 0x300B: // PR_SEARCH_KEY Record Header 2
02520                     LIST_COPY_EMAIL_STR("Record Search 2", item->email->outlook_search_key);
02521                     break;
02522                 case 0x35DF: // PR_VALID_FOLDER_MASK
02523                     LIST_COPY_STORE_INT32("Valid Folder Mask", item->message_store->valid_mask);
02524                     break;
02525                 case 0x35E0: // PR_IPM_SUBTREE_ENTRYID Top of Personal Folder Record
02526                     LIST_COPY_STORE_ENTRYID("Top of Personal Folder Record", item->message_store->top_of_personal_folder);
02527                     break;
02528                 case 0x35E2: // PR_IPM_OUTBOX_ENTRYID
02529                     LIST_COPY_STORE_ENTRYID("Default Outbox Folder record", item->message_store->default_outbox_folder);
02530                     break;
02531                 case 0x35E3: // PR_IPM_WASTEBASKET_ENTRYID
02532                     LIST_COPY_STORE_ENTRYID("Deleted Items Folder record", item->message_store->deleted_items_folder);
02533                     break;
02534                 case 0x35E4: // PR_IPM_SENTMAIL_ENTRYID
02535                     LIST_COPY_STORE_ENTRYID("Sent Items Folder record", item->message_store->sent_items_folder);
02536                     break;
02537                 case 0x35E5: // PR_VIEWS_ENTRYID
02538                     LIST_COPY_STORE_ENTRYID("User Views Folder record", item->message_store->user_views_folder);
02539                     break;
02540                 case 0x35E6: // PR_COMMON_VIEWS_ENTRYID
02541                     LIST_COPY_STORE_ENTRYID("Common View Folder record", item->message_store->common_view_folder);
02542                     break;
02543                 case 0x35E7: // PR_FINDER_ENTRYID
02544                     LIST_COPY_STORE_ENTRYID("Search Root Folder record", item->message_store->search_root_folder);
02545                     break;
02546                 case 0x3602: // PR_CONTENT_COUNT Number of emails stored in a folder
02547                     LIST_COPY_FOLDER_INT32("Folder Email Count", item->folder->item_count);
02548                     break;
02549                 case 0x3603: // PR_CONTENT_UNREAD Number of unread emails
02550                     LIST_COPY_FOLDER_INT32("Unread Email Count", item->folder->unseen_item_count);
02551                     break;
02552                 case 0x360A: // PR_SUBFOLDERS Has children
02553                     MALLOC_FOLDER(item);
02554                     LIST_COPY_BOOL("Has Subfolders", item->folder->subfolder);
02555                     break;
02556                 case 0x3613: // PR_CONTAINER_CLASS IPF.x
02557                     LIST_COPY_CSTR(item->ascii_type);
02558                     if (pst_strincmp("IPF.Note", item->ascii_type, 8) == 0)
02559                         item->type = PST_TYPE_NOTE;
02560                     else if (pst_strincmp("IPF.Imap", item->ascii_type, 8) == 0)
02561                         item->type = PST_TYPE_NOTE;
02562                     else if (pst_stricmp("IPF", item->ascii_type) == 0)
02563                         item->type = PST_TYPE_NOTE;
02564                     else if (pst_strincmp("IPF.Contact", item->ascii_type, 11) == 0)
02565                         item->type = PST_TYPE_CONTACT;
02566                     else if (pst_strincmp("IPF.Journal", item->ascii_type, 11) == 0)
02567                         item->type = PST_TYPE_JOURNAL;
02568                     else if (pst_strincmp("IPF.Appointment", item->ascii_type, 15) == 0)
02569                         item->type = PST_TYPE_APPOINTMENT;
02570                     else if (pst_strincmp("IPF.StickyNote", item->ascii_type, 14) == 0)
02571                         item->type = PST_TYPE_STICKYNOTE;
02572                     else if (pst_strincmp("IPF.Task", item->ascii_type, 8) == 0)
02573                         item->type = PST_TYPE_TASK;
02574                     else
02575                         item->type = PST_TYPE_OTHER;
02576 
02577                     DEBUG_INFO(("Container class %s [%"PRIi32"]\n", item->ascii_type, item->type));
02578                     break;
02579                 case 0x3617: // PR_ASSOC_CONTENT_COUNT
02580                     // associated content are items that are attached to this folder
02581                     // but are hidden from users
02582                     LIST_COPY_FOLDER_INT32("Associated Content count", item->folder->assoc_count);
02583                     break;
02584                 case 0x3701: // PR_ATTACH_DATA_OBJ binary data of attachment
02585                     DEBUG_INFO(("Binary Data [Size %i]\n", list->elements[x]->size));
02586                     NULL_CHECK(attach);
02587                     if (!list->elements[x]->data) { //special case
02588                         attach->id2_val = list->elements[x]->type;
02589                         DEBUG_INFO(("Seen a Reference. The data hasn't been loaded yet. [%#"PRIx64"]\n", attach->id2_val));
02590                     } else {
02591                         LIST_COPY_BIN(attach->data);
02592                     }
02593                     break;
02594                 case 0x3704: // PR_ATTACH_FILENAME Attachment filename (8.3)
02595                     NULL_CHECK(attach);
02596                     LIST_COPY_STR("Attachment Filename", attach->filename1);
02597                     break;
02598                 case 0x3705: // PR_ATTACH_METHOD
02599                     NULL_CHECK(attach);
02600                     LIST_COPY_ENUM("Attachment method", attach->method, 0, 7,
02601                         "No Attachment",
02602                         "Attach By Value",
02603                         "Attach By Reference",
02604                         "Attach by Reference Resolve",
02605                         "Attach by Reference Only",
02606                         "Embedded Message",
02607                         "OLE");
02608                     break;
02609                 case 0x3707: // PR_ATTACH_LONG_FILENAME Attachment filename (long?)
02610                     NULL_CHECK(attach);
02611                     LIST_COPY_STR("Attachment Filename long", attach->filename2);
02612                     break;
02613                 case 0x370B: // PR_RENDERING_POSITION
02614                     // position in characters that the attachment appears in the plain text body
02615                     NULL_CHECK(attach);
02616                     LIST_COPY_INT32("Attachment Position", attach->position);
02617                     break;
02618                 case 0x370E: // PR_ATTACH_MIME_TAG Mime type of encoding
02619                     NULL_CHECK(attach);
02620                     LIST_COPY_STR("Attachment mime encoding", attach->mimetype);
02621                     break;
02622                 case 0x3710: // PR_ATTACH_MIME_SEQUENCE
02623                     // sequence number for mime parts. Includes body
02624                     NULL_CHECK(attach);
02625                     LIST_COPY_INT32("Attachment Mime Sequence", attach->sequence);
02626                     break;
02627                 case 0x3A00: // PR_ACCOUNT
02628                     LIST_COPY_CONTACT_STR("Contact's Account name", item->contact->account_name);
02629                     break;
02630                 case 0x3A01: // PR_ALTERNATE_RECIPIENT
02631                     DEBUG_INFO(("Contact Alternate Recipient - NOT PROCESSED\n"));
02632                     break;
02633                 case 0x3A02: // PR_CALLBACK_TELEPHONE_NUMBER
02634                     LIST_COPY_CONTACT_STR("Callback telephone number", item->contact->callback_phone);
02635                     break;
02636                 case 0x3A03: // PR_CONVERSION_PROHIBITED
02637                     LIST_COPY_EMAIL_BOOL("Message Conversion Prohibited", item->email->conversion_prohibited);
02638                     break;
02639                 case 0x3A05: // PR_GENERATION suffix
02640                     LIST_COPY_CONTACT_STR("Contacts Suffix", item->contact->suffix);
02641                     break;
02642                 case 0x3A06: // PR_GIVEN_NAME Contact's first name
02643                     LIST_COPY_CONTACT_STR("Contacts First Name", item->contact->first_name);
02644                     break;
02645                 case 0x3A07: // PR_GOVERNMENT_ID_NUMBER
02646                     LIST_COPY_CONTACT_STR("Contacts Government ID Number", item->contact->gov_id);
02647                     break;
02648                 case 0x3A08: // PR_BUSINESS_TELEPHONE_NUMBER
02649                     LIST_COPY_CONTACT_STR("Business Telephone Number", item->contact->business_phone);
02650                     break;
02651                 case 0x3A09: // PR_HOME_TELEPHONE_NUMBER
02652                     LIST_COPY_CONTACT_STR("Home Telephone Number", item->contact->home_phone);
02653                     break;
02654                 case 0x3A0A: // PR_INITIALS Contact's Initials
02655                     LIST_COPY_CONTACT_STR("Contacts Initials", item->contact->initials);
02656                     break;
02657                 case 0x3A0B: // PR_KEYWORD
02658                     LIST_COPY_CONTACT_STR("Keyword", item->contact->keyword);
02659                     break;
02660                 case 0x3A0C: // PR_LANGUAGE
02661                     LIST_COPY_CONTACT_STR("Contact's Language", item->contact->language);
02662                     break;
02663                 case 0x3A0D: // PR_LOCATION
02664                     LIST_COPY_CONTACT_STR("Contact's Location", item->contact->location);
02665                     break;
02666                 case 0x3A0E: // PR_MAIL_PERMISSION - Can the recipient receive and send email
02667                     LIST_COPY_CONTACT_BOOL("Mail Permission", item->contact->mail_permission);
02668                     break;
02669                 case 0x3A0F: // PR_MHS_COMMON_NAME
02670                     LIST_COPY_CONTACT_STR("MHS Common Name", item->contact->common_name);
02671                     break;
02672                 case 0x3A10: // PR_ORGANIZATIONAL_ID_NUMBER
02673                     LIST_COPY_CONTACT_STR("Organizational ID #", item->contact->org_id);
02674                     break;
02675                 case 0x3A11: // PR_SURNAME Contact's Surname
02676                     LIST_COPY_CONTACT_STR("Contacts Surname", item->contact->surname);
02677                     break;
02678                 case 0x3A12: // PR_ORIGINAL_ENTRY_ID
02679                     DEBUG_INFO(("Original Entry ID - NOT PROCESSED\n"));
02680                     break;
02681                 case 0x3A13: // PR_ORIGINAL_DISPLAY_NAME
02682                     DEBUG_INFO(("Original Display Name - NOT PROCESSED\n"));
02683                     break;
02684                 case 0x3A14: // PR_ORIGINAL_SEARCH_KEY
02685                     DEBUG_INFO(("Original Search Key - NOT PROCESSED\n"));
02686                     break;
02687                 case 0x3A15: // PR_POSTAL_ADDRESS
02688                     LIST_COPY_CONTACT_STR("Default Postal Address", item->contact->def_postal_address);
02689                     break;
02690                 case 0x3A16: // PR_COMPANY_NAME
02691                     LIST_COPY_CONTACT_STR("Company Name", item->contact->company_name);
02692                     break;
02693                 case 0x3A17: // PR_TITLE - Job Title
02694                     LIST_COPY_CONTACT_STR("Job Title", item->contact->job_title);
02695                     break;
02696                 case 0x3A18: // PR_DEPARTMENT_NAME
02697                     LIST_COPY_CONTACT_STR("Department Name", item->contact->department);
02698                     break;
02699                 case 0x3A19: // PR_OFFICE_LOCATION
02700                     LIST_COPY_CONTACT_STR("Office Location", item->contact->office_loc);
02701                     break;
02702                 case 0x3A1A: // PR_PRIMARY_TELEPHONE_NUMBER
02703                     LIST_COPY_CONTACT_STR("Primary Telephone", item->contact->primary_phone);
02704                     break;
02705                 case 0x3A1B: // PR_BUSINESS2_TELEPHONE_NUMBER
02706                     LIST_COPY_CONTACT_STR("Business Phone Number 2", item->contact->business_phone2);
02707                     break;
02708                 case 0x3A1C: // PR_MOBILE_TELEPHONE_NUMBER
02709                     LIST_COPY_CONTACT_STR("Mobile Phone Number", item->contact->mobile_phone);
02710                     break;
02711                 case 0x3A1D: // PR_RADIO_TELEPHONE_NUMBER
02712                     LIST_COPY_CONTACT_STR("Radio Phone Number", item->contact->radio_phone);
02713                     break;
02714                 case 0x3A1E: // PR_CAR_TELEPHONE_NUMBER
02715                     LIST_COPY_CONTACT_STR("Car Phone Number", item->contact->car_phone);
02716                     break;
02717                 case 0x3A1F: // PR_OTHER_TELEPHONE_NUMBER
02718                     LIST_COPY_CONTACT_STR("Other Phone Number", item->contact->other_phone);
02719                     break;
02720                 case 0x3A20: // PR_TRANSMITTABLE_DISPLAY_NAME
02721                     LIST_COPY_CONTACT_STR("Transmittable Display Name", item->contact->transmittable_display_name);
02722                     break;
02723                 case 0x3A21: // PR_PAGER_TELEPHONE_NUMBER
02724                     LIST_COPY_CONTACT_STR("Pager Phone Number", item->contact->pager_phone);
02725                     break;
02726                 case 0x3A22: // PR_USER_CERTIFICATE
02727                     DEBUG_INFO(("User Certificate - NOT PROCESSED\n"));
02728                     break;
02729                 case 0x3A23: // PR_PRIMARY_FAX_NUMBER
02730                     LIST_COPY_CONTACT_STR("Primary Fax Number", item->contact->primary_fax);
02731                     break;
02732                 case 0x3A24: // PR_BUSINESS_FAX_NUMBER
02733                     LIST_COPY_CONTACT_STR("Business Fax Number", item->contact->business_fax);
02734                     break;
02735                 case 0x3A25: // PR_HOME_FAX_NUMBER
02736                     LIST_COPY_CONTACT_STR("Home Fax Number", item->contact->home_fax);
02737                     break;
02738                 case 0x3A26: // PR_BUSINESS_ADDRESS_COUNTRY
02739                     LIST_COPY_CONTACT_STR("Business Address Country", item->contact->business_country);
02740                     break;
02741                 case 0x3A27: // PR_BUSINESS_ADDRESS_CITY
02742                     LIST_COPY_CONTACT_STR("Business Address City", item->contact->business_city);
02743                     break;
02744                 case 0x3A28: // PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE
02745                     LIST_COPY_CONTACT_STR("Business Address State", item->contact->business_state);
02746                     break;
02747                 case 0x3A29: // PR_BUSINESS_ADDRESS_STREET
02748                     LIST_COPY_CONTACT_STR("Business Address Street", item->contact->business_street);
02749                     break;
02750                 case 0x3A2A: // PR_BUSINESS_POSTAL_CODE
02751                     LIST_COPY_CONTACT_STR("Business Postal Code", item->contact->business_postal_code);
02752                     break;
02753                 case 0x3A2B: // PR_BUSINESS_PO_BOX
02754                     LIST_COPY_CONTACT_STR("Business PO Box", item->contact->business_po_box);
02755                     break;
02756                 case 0x3A2C: // PR_TELEX_NUMBER
02757                     LIST_COPY_CONTACT_STR("Telex Number", item->contact->telex);
02758                     break;
02759                 case 0x3A2D: // PR_ISDN_NUMBER
02760                     LIST_COPY_CONTACT_STR("ISDN Number", item->contact->isdn_phone);
02761                     break;
02762                 case 0x3A2E: // PR_ASSISTANT_TELEPHONE_NUMBER
02763                     LIST_COPY_CONTACT_STR("Assistant Phone Number", item->contact->assistant_phone);
02764                     break;
02765                 case 0x3A2F: // PR_HOME2_TELEPHONE_NUMBER
02766                     LIST_COPY_CONTACT_STR("Home Phone 2", item->contact->home_phone2);
02767                     break;
02768                 case 0x3A30: // PR_ASSISTANT
02769                     LIST_COPY_CONTACT_STR("Assistant's Name", item->contact->assistant_name);
02770                     break;
02771                 case 0x3A40: // PR_SEND_RICH_INFO
02772                     LIST_COPY_CONTACT_BOOL("Can receive Rich Text", item->contact->rich_text);
02773                     break;
02774                 case 0x3A41: // PR_WEDDING_ANNIVERSARY
02775                     LIST_COPY_CONTACT_TIME("Wedding Anniversary", item->contact->wedding_anniversary);
02776                     break;
02777                 case 0x3A42: // PR_BIRTHDAY
02778                     LIST_COPY_CONTACT_TIME("Birthday", item->contact->birthday);
02779                     break;
02780                 case 0x3A43: // PR_HOBBIES
02781                     LIST_COPY_CONTACT_STR("Hobbies", item->contact->hobbies);
02782                     break;
02783                 case 0x3A44: // PR_MIDDLE_NAME
02784                     LIST_COPY_CONTACT_STR("Middle Name", item->contact->middle_name);
02785                     break;
02786                 case 0x3A45: // PR_DISPLAY_NAME_PREFIX
02787                     LIST_COPY_CONTACT_STR("Display Name Prefix (Title)", item->contact->display_name_prefix);
02788                     break;
02789                 case 0x3A46: // PR_PROFESSION
02790                     LIST_COPY_CONTACT_STR("Profession", item->contact->profession);
02791                     break;
02792                 case 0x3A47: // PR_PREFERRED_BY_NAME
02793                     LIST_COPY_CONTACT_STR("Preferred By Name", item->contact->pref_name);
02794                     break;
02795                 case 0x3A48: // PR_SPOUSE_NAME
02796                     LIST_COPY_CONTACT_STR("Spouse's Name", item->contact->spouse_name);
02797                     break;
02798                 case 0x3A49: // PR_COMPUTER_NETWORK_NAME
02799                     LIST_COPY_CONTACT_STR("Computer Network Name", item->contact->computer_name);
02800                     break;
02801                 case 0x3A4A: // PR_CUSTOMER_ID
02802                     LIST_COPY_CONTACT_STR("Customer ID", item->contact->customer_id);
02803                     break;
02804                 case 0x3A4B: // PR_TTYTDD_PHONE_NUMBER
02805                     LIST_COPY_CONTACT_STR("TTY/TDD Phone", item->contact->ttytdd_phone);
02806                     break;
02807                 case 0x3A4C: // PR_FTP_SITE
02808                     LIST_COPY_CONTACT_STR("Ftp Site", item->contact->ftp_site);
02809                     break;
02810                 case 0x3A4D: // PR_GENDER
02811                     LIST_COPY_CONTACT_ENUM16("Gender", item->contact->gender, 0, 3, "Unspecified", "Female", "Male");
02812                     break;
02813                 case 0x3A4E: // PR_MANAGER_NAME
02814                     LIST_COPY_CONTACT_STR("Manager's Name", item->contact->manager_name);
02815                     break;
02816                 case 0x3A4F: // PR_NICKNAME
02817                     LIST_COPY_CONTACT_STR("Nickname", item->contact->nickname);
02818                     break;
02819                 case 0x3A50: // PR_PERSONAL_HOME_PAGE
02820                     LIST_COPY_CONTACT_STR("Personal Home Page", item->contact->personal_homepage);
02821                     break;
02822                 case 0x3A51: // PR_BUSINESS_HOME_PAGE
02823                     LIST_COPY_CONTACT_STR("Business Home Page", item->contact->business_homepage);
02824                     break;
02825                 case 0x3A57: // PR_COMPANY_MAIN_PHONE_NUMBER
02826                     LIST_COPY_CONTACT_STR("Company Main Phone", item->contact->company_main_phone);
02827                     break;
02828                 case 0x3A58: // PR_CHILDRENS_NAMES
02829                     DEBUG_INFO(("Children's Names - NOT PROCESSED\n"));
02830                     break;
02831                 case 0x3A59: // PR_HOME_ADDRESS_CITY
02832                     LIST_COPY_CONTACT_STR("Home Address City", item->contact->home_city);
02833                     break;
02834                 case 0x3A5A: // PR_HOME_ADDRESS_COUNTRY
02835                     LIST_COPY_CONTACT_STR("Home Address Country", item->contact->home_country);
02836                     break;
02837                 case 0x3A5B: // PR_HOME_ADDRESS_POSTAL_CODE
02838                     LIST_COPY_CONTACT_STR("Home Address Postal Code", item->contact->home_postal_code);
02839                     break;
02840                 case 0x3A5C: // PR_HOME_ADDRESS_STATE_OR_PROVINCE
02841                     LIST_COPY_CONTACT_STR("Home Address State or Province", item->contact->home_state);
02842                     break;
02843                 case 0x3A5D: // PR_HOME_ADDRESS_STREET
02844                     LIST_COPY_CONTACT_STR("Home Address Street", item->contact->home_street);
02845                     break;
02846                 case 0x3A5E: // PR_HOME_ADDRESS_POST_OFFICE_BOX
02847                     LIST_COPY_CONTACT_STR("Home Address Post Office Box", item->contact->home_po_box);
02848                     break;
02849                 case 0x3A5F: // PR_OTHER_ADDRESS_CITY
02850                     LIST_COPY_CONTACT_STR("Other Address City", item->contact->other_city);
02851                     break;
02852                 case 0x3A60: // PR_OTHER_ADDRESS_COUNTRY
02853                     LIST_COPY_CONTACT_STR("Other Address Country", item->contact->other_country);
02854                     break;
02855                 case 0x3A61: // PR_OTHER_ADDRESS_POSTAL_CODE
02856                     LIST_COPY_CONTACT_STR("Other Address Postal Code", item->contact->other_postal_code);
02857                     break;
02858                 case 0x3A62: // PR_OTHER_ADDRESS_STATE_OR_PROVINCE
02859                     LIST_COPY_CONTACT_STR("Other Address State", item->contact->other_state);
02860                     break;
02861                 case 0x3A63: // PR_OTHER_ADDRESS_STREET
02862                     LIST_COPY_CONTACT_STR("Other Address Street", item->contact->other_street);
02863                     break;
02864                 case 0x3A64: // PR_OTHER_ADDRESS_POST_OFFICE_BOX
02865                     LIST_COPY_CONTACT_STR("Other Address Post Office box", item->contact->other_po_box);
02866                     break;
02867                 case 0x3FDE: // PR_INTERNET_CPID
02868                     LIST_COPY_INT32("Internet code page", item->internet_cpid);
02869                     break;
02870                 case 0x3FFD: // PR_MESSAGE_CODEPAGE
02871                     LIST_COPY_INT32("Message code page", item->message_codepage);
02872                     break;
02873                 case 0x65E3: // PR_PREDECESSOR_CHANGE_LIST
02874                     LIST_COPY_BIN(item->predecessor_change);
02875                     DEBUG_INFO(("Predecessor Change\n"));
02876                     DEBUG_HEXDUMP(item->predecessor_change.data, item->predecessor_change.size);
02877                     break;
02878                 case 0x67F2: // ID2 value of the attachment
02879                     NULL_CHECK(attach);
02880                     LIST_COPY_INT32("Attachment ID2 value", ut);
02881                     attach->id2_val = ut;
02882                     break;
02883                 case 0x67FF: // Extra Property Identifier (Password CheckSum)
02884                     LIST_COPY_STORE_INT32("Password checksum", item->message_store->pwd_chksum);
02885                     break;
02886                 case 0x6F02: // Secure HTML Body
02887                     LIST_COPY_EMAIL_BIN("Secure HTML Body", item->email->encrypted_htmlbody);
02888                     break;
02889                 case 0x6F04: // Secure Text Body
02890                     LIST_COPY_EMAIL_BIN("Secure Text Body", item->email->encrypted_body);
02891                     break;
02892                 case 0x7C07: // top of folders ENTRYID
02893                     LIST_COPY_STORE_ENTRYID("Top of folders RecID", item->message_store->top_of_folder);
02894                     break;
02895                 case 0x8005: // Contact's Fullname
02896                     LIST_COPY_CONTACT_STR("Contact Fullname", item->contact->fullname);
02897                     break;
02898                 case 0x801A: // Full Home Address
02899                     LIST_COPY_CONTACT_STR("Home Address", item->contact->home_address);
02900                     break;
02901                 case 0x801B: // Full Business Address
02902                     LIST_COPY_CONTACT_STR("Business Address", item->contact->business_address);
02903                     break;
02904                 case 0x801C: // Full Other Address
02905                     LIST_COPY_CONTACT_STR("Other Address", item->contact->other_address);
02906                     break;
02907                 case 0x8045: // Work address street
02908                     LIST_COPY_CONTACT_STR("Work address street", item->contact->work_address_street);
02909                     break;
02910                 case 0x8046: // Work address city
02911                     LIST_COPY_CONTACT_STR("Work address city", item->contact->work_address_city);
02912                     break;
02913                 case 0x8047: // Work address state
02914                     LIST_COPY_CONTACT_STR("Work address state", item->contact->work_address_state);
02915                     break;
02916                 case 0x8048: // Work address postalcode
02917                     LIST_COPY_CONTACT_STR("Work address postalcode", item->contact->work_address_postalcode);
02918                     break;
02919                 case 0x8049: // Work address country
02920                     LIST_COPY_CONTACT_STR("Work address country", item->contact->work_address_country);
02921                     break;
02922                 case 0x804A: // Work address postofficebox
02923                     LIST_COPY_CONTACT_STR("Work address postofficebox", item->contact->work_address_postofficebox);
02924                     break;
02925                 case 0x8082: // Email Address 1 Transport
02926                     LIST_COPY_CONTACT_STR("Email Address 1 Transport", item->contact->address1_transport);
02927                     break;
02928                 case 0x8083: // Email Address 1 Address
02929                     LIST_COPY_CONTACT_STR("Email Address 1 Address", item->contact->address1);
02930                     break;
02931                 case 0x8084: // Email Address 1 Description
02932                     LIST_COPY_CONTACT_STR("Email Address 1 Description", item->contact->address1_desc);
02933                     break;
02934                 case 0x8085: // Email Address 1 Record
02935                     LIST_COPY_CONTACT_STR("Email Address 1 Record", item->contact->address1a);
02936                     break;
02937                 case 0x8092: // Email Address 2 Transport
02938                     LIST_COPY_CONTACT_STR("Email Address 2 Transport", item->contact->address2_transport);
02939                     break;
02940                 case 0x8093: // Email Address 2 Address
02941                     LIST_COPY_CONTACT_STR("Email Address 2 Address", item->contact->address2);
02942                     break;
02943                 case 0x8094: // Email Address 2 Description
02944                     LIST_COPY_CONTACT_STR("Email Address 2 Description", item->contact->address2_desc);
02945                     break;
02946                 case 0x8095: // Email Address 2 Record
02947                     LIST_COPY_CONTACT_STR("Email Address 2 Record", item->contact->address2a);
02948                     break;
02949                 case 0x80A2: // Email Address 3 Transport
02950                     LIST_COPY_CONTACT_STR("Email Address 3 Transport", item->contact->address3_transport);
02951                     break;
02952                 case 0x80A3: // Email Address 3 Address
02953                     LIST_COPY_CONTACT_STR("Email Address 3 Address", item->contact->address3);
02954                     break;
02955                 case 0x80A4: // Email Address 3 Description
02956                     LIST_COPY_CONTACT_STR("Email Address 3 Description", item->contact->address3_desc);
02957                     break;
02958                 case 0x80A5: // Email Address 3 Record
02959                     LIST_COPY_CONTACT_STR("Email Address 3 Record", item->contact->address3a);
02960                     break;
02961                 case 0x80D8: // Internet Free/Busy
02962                     LIST_COPY_CONTACT_STR("Internet Free/Busy", item->contact->free_busy_address);
02963                     break;
02964                 case 0x8205: // PR_OUTLOOK_EVENT_SHOW_TIME_AS
02965                     LIST_COPY_APPT_ENUM("Appointment shows as", item->appointment->showas, 0, 4,
02966                         "Free", "Tentative", "Busy", "Out Of Office");
02967                     break;
02968                 case 0x8208: // PR_OUTLOOK_EVENT_LOCATION
02969                     LIST_COPY_APPT_STR("Appointment Location", item->appointment->location);
02970                     break;
02971                 case 0x820d: // PR_OUTLOOK_EVENT_START_DATE
02972                     LIST_COPY_APPT_TIME("Appointment Date Start", item->appointment->start);
02973                     break;
02974                 case 0x820e: // PR_OUTLOOK_EVENT_START_END
02975                     LIST_COPY_APPT_TIME("Appointment Date End", item->appointment->end);
02976                     break;
02977                 case 0x8214: // Label for an appointment
02978                     LIST_COPY_APPT_ENUM("Label for appointment", item->appointment->label, 0, 11,
02979                         "None",
02980                         "Important",
02981                         "Business",
02982                         "Personal",
02983                         "Vacation",
02984                         "Must Attend",
02985                         "Travel Required",
02986                         "Needs Preparation",
02987                         "Birthday",
02988                         "Anniversary",
02989                         "Phone Call");
02990                     break;
02991                 case 0x8215: // PR_OUTLOOK_EVENT_ALL_DAY
02992                     LIST_COPY_APPT_BOOL("All day flag", item->appointment->all_day);
02993                     break;
02994                 case 0x8216: // PR_OUTLOOK_EVENT_RECURRENCE_DATA
02995                     LIST_COPY_APPT_BIN("Appointment recurrence data", item->appointment->recurrence_data);
02996                     break;
02997                 case 0x8223: // PR_OUTLOOK_EVENT_IS_RECURRING
02998                     LIST_COPY_APPT_BOOL("Is recurring", item->appointment->is_recurring);
02999                     break;
03000                 case 0x8231: // Recurrence type
03001                     LIST_COPY_APPT_ENUM("Appointment recurrence type ", item->appointment->recurrence_type, 0, 5,
03002                         "None",
03003                         "Daily",
03004                         "Weekly",
03005                         "Monthly",
03006                         "Yearly");
03007                     break;
03008                 case 0x8232: // Recurrence description
03009                     LIST_COPY_APPT_STR("Appointment recurrence description", item->appointment->recurrence_description);
03010                     break;
03011                 case 0x8234: // TimeZone as String
03012                     LIST_COPY_APPT_STR("TimeZone of times", item->appointment->timezonestring);
03013                     break;
03014                 case 0x8235: // PR_OUTLOOK_EVENT_RECURRENCE_START
03015                     LIST_COPY_APPT_TIME("Recurrence Start Date", item->appointment->recurrence_start);
03016                     break;
03017                 case 0x8236: // PR_OUTLOOK_EVENT_RECURRENCE_END
03018                     LIST_COPY_APPT_TIME("Recurrence End Date", item->appointment->recurrence_end);
03019                     break;
03020                 case 0x8501: // PR_OUTLOOK_COMMON_REMINDER_MINUTES_BEFORE
03021                     LIST_COPY_APPT_INT32("Alarm minutes", item->appointment->alarm_minutes);
03022                     break;
03023                 case 0x8503: // PR_OUTLOOK_COMMON_REMINDER_SET
03024                     LIST_COPY_APPT_BOOL("Reminder alarm", item->appointment->alarm);
03025                     break;
03026                 case 0x8516: // Common start
03027                     DEBUG_INFO(("Common Start Date - %s\n", pst_fileTimeToAscii((FILETIME*)list->elements[x]->data, time_buffer)));
03028                     break;
03029                 case 0x8517: // Common end
03030                     DEBUG_INFO(("Common End Date - %s\n", pst_fileTimeToAscii((FILETIME*)list->elements[x]->data, time_buffer)));
03031                     break;
03032                 case 0x851f: // Play reminder sound filename
03033                     LIST_COPY_APPT_STR("Appointment reminder sound filename", item->appointment->alarm_filename);
03034                     break;
03035                 case 0x8530: // Followup
03036                     LIST_COPY_CONTACT_STR("Followup String", item->contact->followup);
03037                     break;
03038                 case 0x8534: // Mileage
03039                     LIST_COPY_CONTACT_STR("Mileage", item->contact->mileage);
03040                     break;
03041                 case 0x8535: // Billing Information
03042                     LIST_COPY_CONTACT_STR("Billing Information", item->contact->billing_information);
03043                     break;
03044                 case 0x8554: // PR_OUTLOOK_VERSION
03045                     LIST_COPY_STR("Outlook Version", item->outlook_version);
03046                     break;
03047                 case 0x8560: // Appointment Reminder Time
03048                     LIST_COPY_APPT_TIME("Appointment Reminder Time", item->appointment->reminder);
03049                     break;
03050                 case 0x8700: // Journal Type
03051                     LIST_COPY_JOURNAL_STR("Journal Entry Type", item->journal->type);
03052                     break;
03053                 case 0x8706: // Journal Start date/time
03054                     LIST_COPY_JOURNAL_TIME("Start Timestamp", item->journal->start);
03055                     break;
03056                 case 0x8708: // Journal End date/time
03057                     LIST_COPY_JOURNAL_TIME("End Timestamp", item->journal->end);
03058                     break;
03059                 case 0x8712: // Journal Type Description
03060                     LIST_COPY_JOURNAL_STR("Journal description", item->journal->description);
03061                     break;
03062                 default:
03063                     if (list->elements[x]->type == (uint32_t)0x0002) {
03064                         DEBUG_WARN(("Unknown type %#x 16bit int = %hi\n", list->elements[x]->mapi_id,
03065                             *(int16_t*)list->elements[x]->data));
03066 
03067                     } else if (list->elements[x]->type == (uint32_t)0x0003) {
03068                         DEBUG_WARN(("Unknown type %#x 32bit int = %i\n", list->elements[x]->mapi_id,
03069                             *(int32_t*)list->elements[x]->data));
03070 
03071                     } else if (list->elements[x]->type == (uint32_t)0x0004) {
03072                         DEBUG_WARN(("Unknown type %#x 4-byte floating [size = %#x]\n", list->elements[x]->mapi_id,
03073                             list->elements[x]->size));
03074                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03075 
03076                     } else if (list->elements[x]->type == (uint32_t)0x0005) {
03077                         DEBUG_WARN(("Unknown type %#x double floating [size = %#x]\n", list->elements[x]->mapi_id,
03078                             list->elements[x]->size));
03079                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03080 
03081                     } else if (list->elements[x]->type == (uint32_t)0x0006) {
03082                         DEBUG_WARN(("Unknown type %#x signed 64bit int = %"PRIi64"\n", list->elements[x]->mapi_id,
03083                             *(int64_t*)list->elements[x]->data));
03084                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03085 
03086                     } else if (list->elements[x]->type == (uint32_t)0x0007) {
03087                         DEBUG_WARN(("Unknown type %#x application time [size = %#x]\n", list->elements[x]->mapi_id,
03088                             list->elements[x]->size));
03089                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03090 
03091                     } else if (list->elements[x]->type == (uint32_t)0x000a) {
03092                         DEBUG_WARN(("Unknown type %#x 32bit error value = %i\n", list->elements[x]->mapi_id,
03093                             *(int32_t*)list->elements[x]->data));
03094 
03095                     } else if (list->elements[x]->type == (uint32_t)0x000b) {
03096                         DEBUG_WARN(("Unknown type %#x 16bit boolean = %s [%hi]\n", list->elements[x]->mapi_id,
03097                             (*((int16_t*)list->elements[x]->data)!=0?"True":"False"),
03098                             *((int16_t*)list->elements[x]->data)));
03099 
03100                     } else if (list->elements[x]->type == (uint32_t)0x000d) {
03101                         DEBUG_WARN(("Unknown type %#x Embedded object [size = %#x]\n", list->elements[x]->mapi_id,
03102                             list->elements[x]->size));
03103                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03104 
03105                     } else if (list->elements[x]->type == (uint32_t)0x0014) {
03106                         DEBUG_WARN(("Unknown type %#x signed 64bit int = %"PRIi64"\n", list->elements[x]->mapi_id,
03107                             *(int64_t*)list->elements[x]->data));
03108                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03109 
03110                     } else if (list->elements[x]->type == (uint32_t)0x001e) {
03111                         DEBUG_WARN(("Unknown type %#x String Data = \"%s\"\n", list->elements[x]->mapi_id,
03112                             list->elements[x]->data));
03113 
03114                     } else if (list->elements[x]->type == (uint32_t)0x001f) {
03115                         DEBUG_WARN(("Unknown type %#x Unicode String Data [size = %#x]\n", list->elements[x]->mapi_id,
03116                             list->elements[x]->size));
03117                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03118 
03119                     } else if (list->elements[x]->type == (uint32_t)0x0040) {
03120                         DEBUG_WARN(("Unknown type %#x Date = \"%s\"\n", list->elements[x]->mapi_id,
03121                             pst_fileTimeToAscii((FILETIME*)list->elements[x]->data, time_buffer)));
03122 
03123                     } else if (list->elements[x]->type == (uint32_t)0x0048) {
03124                         DEBUG_WARN(("Unknown type %#x OLE GUID [size = %#x]\n", list->elements[x]->mapi_id,
03125                             list->elements[x]->size));
03126                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03127 
03128                     } else if (list->elements[x]->type == (uint32_t)0x0102) {
03129                         DEBUG_WARN(("Unknown type %#x Binary Data [size = %#x]\n", list->elements[x]->mapi_id,
03130                             list->elements[x]->size));
03131                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03132 
03133                     } else if (list->elements[x]->type == (uint32_t)0x1003) {
03134                         DEBUG_WARN(("Unknown type %#x Array of 32 bit values [size = %#x]\n", list->elements[x]->mapi_id,
03135                             list->elements[x]->size));
03136                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03137 
03138                     } else if (list->elements[x]->type == (uint32_t)0x1014) {
03139                         DEBUG_WARN(("Unknown type %#x Array of 64 bit values [siize = %#x]\n", list->elements[x]->mapi_id,
03140                             list->elements[x]->size));
03141                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03142 
03143                     } else if (list->elements[x]->type == (uint32_t)0x101e) {
03144                         DEBUG_WARN(("Unknown type %#x Array of Strings [size = %#x]\n", list->elements[x]->mapi_id,
03145                             list->elements[x]->size));
03146                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03147 
03148                     } else if (list->elements[x]->type == (uint32_t)0x101f) {
03149                         DEBUG_WARN(("Unknown type %#x Array of Unicode Strings [size = %#x]\n", list->elements[x]->mapi_id,
03150                             list->elements[x]->size));
03151                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03152 
03153                     } else if (list->elements[x]->type == (uint32_t)0x1102) {
03154                         DEBUG_WARN(("Unknown type %#x Array of binary data blobs [size = %#x]\n", list->elements[x]->mapi_id,
03155                             list->elements[x]->size));
03156                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03157 
03158                     } else {
03159                         DEBUG_WARN(("Unknown type %#x Not Printable [%#x]\n", list->elements[x]->mapi_id,
03160                             list->elements[x]->type));
03161                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03162                     }
03163 
03164                     if (list->elements[x]->data) {
03165                         free(list->elements[x]->data);
03166                         list->elements[x]->data = NULL;
03167                     }
03168             }
03169         }
03170         list = list->next;
03171         if (attach) attach = attach->next;
03172     }
03173     DEBUG_RET();
03174     return 0;
03175 }
03176 
03177 
03178 static void pst_free_list(pst_mapi_object *list) {
03179     pst_mapi_object *l;
03180     DEBUG_ENT("pst_free_list");
03181     while (list) {
03182         if (list->elements) {
03183             int32_t x;
03184             for (x=0; x < list->orig_count; x++) {
03185                 if (list->elements[x]) {
03186                     if (list->elements[x]->data) free(list->elements[x]->data);
03187                     free(list->elements[x]);
03188                 }
03189             }
03190             free(list->elements);
03191         }
03192         l = list->next;
03193         free (list);
03194         list = l;
03195     }
03196     DEBUG_RET();
03197 }
03198 
03199 
03200 static void pst_free_id2(pst_id2_tree * head) {
03201     pst_id2_tree *t;
03202     DEBUG_ENT("pst_free_id2");
03203     while (head) {
03204         pst_free_id2(head->child);
03205         t = head->next;
03206         free(head);
03207         head = t;
03208     }
03209     DEBUG_RET();
03210 }
03211 
03212 
03213 static void pst_free_id (pst_index_ll *head) {
03214     pst_index_ll *t;
03215     DEBUG_ENT("pst_free_id");
03216     while (head) {
03217         t = head->next;
03218         free(head);
03219         head = t;
03220     }
03221     DEBUG_RET();
03222 }
03223 
03224 
03225 static void pst_free_desc (pst_desc_tree *head) {
03226     pst_desc_tree *t;
03227     DEBUG_ENT("pst_free_desc");
03228     while (head) {
03229         pst_free_desc(head->child);
03230         t = head->next;
03231         free(head);
03232         head = t;
03233     }
03234     DEBUG_RET();
03235 }
03236 
03237 
03238 static void pst_free_xattrib(pst_x_attrib_ll *x) {
03239     pst_x_attrib_ll *t;
03240     DEBUG_ENT("pst_free_xattrib");
03241     while (x) {
03242         if (x->data) free(x->data);
03243         t = x->next;
03244         free(x);
03245         x = t;
03246     }
03247     DEBUG_RET();
03248 }
03249 
03250 
03251 static pst_id2_tree * pst_build_id2(pst_file *pf, pst_index_ll* list) {
03252     pst_block_header block_head;
03253     pst_id2_tree *head = NULL, *tail = NULL;
03254     uint16_t x = 0;
03255     char *b_ptr = NULL;
03256     char *buf = NULL;
03257     pst_id2_assoc id2_rec;
03258     pst_index_ll *i_ptr = NULL;
03259     pst_id2_tree *i2_ptr = NULL;
03260     DEBUG_ENT("pst_build_id2");
03261 
03262     if (pst_read_block_size(pf, list->offset, list->size, &buf) < list->size) {
03263         //an error occured in block read
03264         DEBUG_WARN(("block read error occured. offset = %#"PRIx64", size = %#"PRIx64"\n", list->offset, list->size));
03265         if (buf) free(buf);
03266         DEBUG_RET();
03267         return NULL;
03268     }
03269     DEBUG_HEXDUMPC(buf, list->size, 16);
03270 
03271     memcpy(&block_head, buf, sizeof(block_head));
03272     LE16_CPU(block_head.type);
03273     LE16_CPU(block_head.count);
03274 
03275     if (block_head.type != (uint16_t)0x0002) { // some sort of constant?
03276         DEBUG_WARN(("Unknown constant [%#hx] at start of id2 values [offset %#"PRIx64"].\n", block_head.type, list->offset));
03277         if (buf) free(buf);
03278         DEBUG_RET();
03279         return NULL;
03280     }
03281 
03282     DEBUG_INFO(("ID %#"PRIx64" is likely to be a description record. Count is %i (offset %#"PRIx64")\n",
03283             list->i_id, block_head.count, list->offset));
03284     x = 0;
03285     b_ptr = buf + ((pf->do_read64) ? 0x08 : 0x04);
03286     while (x < block_head.count) {
03287         b_ptr += pst_decode_assoc(pf, &id2_rec, b_ptr);
03288         DEBUG_INFO(("id2 = %#x, id = %#"PRIx64", child id = %#"PRIx64"\n", id2_rec.id2, id2_rec.id, id2_rec.child_id));
03289         if ((i_ptr = pst_getID(pf, id2_rec.id)) == NULL) {
03290             DEBUG_WARN(("%#"PRIx64" - Not Found\n", id2_rec.id));
03291         } else {
03292             DEBUG_INFO(("%#"PRIx64" - Offset %#"PRIx64", u1 %#"PRIx64", Size %"PRIi64"(%#"PRIx64")\n",
03293                          i_ptr->i_id, i_ptr->offset, i_ptr->u1, i_ptr->size, i_ptr->size));
03294             // add it to the tree
03295             i2_ptr = (pst_id2_tree*) pst_malloc(sizeof(pst_id2_tree));
03296             i2_ptr->id2   = id2_rec.id2;
03297             i2_ptr->id    = i_ptr;
03298             i2_ptr->child = NULL;
03299             i2_ptr->next  = NULL;
03300             if (!head) head = i2_ptr;
03301             if (tail)  tail->next = i2_ptr;
03302             tail = i2_ptr;
03303             if (id2_rec.child_id) {
03304                 if ((i_ptr = pst_getID(pf, id2_rec.child_id)) == NULL) {
03305                     DEBUG_WARN(("child id [%#"PRIx64"] not found\n", id2_rec.child_id));
03306                 }
03307                 else {
03308                     i2_ptr->child = pst_build_id2(pf, i_ptr);
03309                 }
03310             }
03311         }
03312         x++;
03313     }
03314     if (buf) free (buf);
03315     DEBUG_RET();
03316     return head;
03317 }
03318 
03319 
03320 static void pst_free_attach(pst_item_attach *attach) {
03321     while (attach) {
03322         pst_item_attach *t;
03323         SAFE_FREE_STR(attach->filename1);
03324         SAFE_FREE_STR(attach->filename2);
03325         SAFE_FREE_STR(attach->mimetype);
03326         SAFE_FREE_BIN(attach->data);
03327         pst_free_id2(attach->id2_head);
03328         t = attach->next;
03329         free(attach);
03330         attach = t;
03331     }
03332 }
03333 
03334 
03335 void pst_freeItem(pst_item *item) {
03336     pst_item_extra_field *et;
03337 
03338     DEBUG_ENT("pst_freeItem");
03339     if (item) {
03340         if (item->email) {
03341             SAFE_FREE(item->email->arrival_date);
03342             SAFE_FREE_STR(item->email->cc_address);
03343             SAFE_FREE_STR(item->email->bcc_address);
03344             SAFE_FREE_BIN(item->email->conversation_index);
03345             SAFE_FREE_BIN(item->email->encrypted_body);
03346             SAFE_FREE_BIN(item->email->encrypted_htmlbody);
03347             SAFE_FREE_STR(item->email->header);
03348             SAFE_FREE_STR(item->email->htmlbody);
03349             SAFE_FREE_STR(item->email->in_reply_to);
03350             SAFE_FREE_STR(item->email->messageid);
03351             SAFE_FREE_STR(item->email->original_bcc);
03352             SAFE_FREE_STR(item->email->original_cc);
03353             SAFE_FREE_STR(item->email->original_to);
03354             SAFE_FREE_STR(item->email->outlook_recipient);
03355             SAFE_FREE_STR(item->email->outlook_recipient_name);
03356             SAFE_FREE_STR(item->email->outlook_recipient2);
03357             SAFE_FREE_STR(item->email->outlook_sender);
03358             SAFE_FREE_STR(item->email->outlook_sender_name);
03359             SAFE_FREE_STR(item->email->outlook_sender2);
03360             SAFE_FREE_STR(item->email->processed_subject);
03361             SAFE_FREE_STR(item->email->recip_access);
03362             SAFE_FREE_STR(item->email->recip_address);
03363             SAFE_FREE_STR(item->email->recip2_access);
03364             SAFE_FREE_STR(item->email->recip2_address);
03365             SAFE_FREE_STR(item->email->reply_to);
03366             SAFE_FREE_STR(item->email->rtf_body_tag);
03367             SAFE_FREE_BIN(item->email->rtf_compressed);
03368             SAFE_FREE_STR(item->email->return_path_address);
03369             SAFE_FREE_STR(item->email->sender_access);
03370             SAFE_FREE_STR(item->email->sender_address);
03371             SAFE_FREE_STR(item->email->sender2_access);
03372             SAFE_FREE_STR(item->email->sender2_address);
03373             SAFE_FREE(item->email->sent_date);
03374             SAFE_FREE(item->email->sentmail_folder);
03375             SAFE_FREE_STR(item->email->sentto_address);
03376             SAFE_FREE_STR(item->email->report_text);
03377             SAFE_FREE(item->email->report_time);
03378             SAFE_FREE_STR(item->email->supplementary_info);
03379             free(item->email);
03380         }
03381         if (item->folder) {
03382             free(item->folder);
03383         }
03384         if (item->message_store) {
03385             SAFE_FREE(item->message_store->top_of_personal_folder);
03386             SAFE_FREE(item->message_store->default_outbox_folder);
03387             SAFE_FREE(item->message_store->deleted_items_folder);
03388             SAFE_FREE(item->message_store->sent_items_folder);
03389             SAFE_FREE(item->message_store->user_views_folder);
03390             SAFE_FREE(item->message_store->common_view_folder);
03391             SAFE_FREE(item->message_store->search_root_folder);
03392             SAFE_FREE(item->message_store->top_of_folder);
03393             free(item->message_store);
03394         }
03395         if (item->contact) {
03396             SAFE_FREE_STR(item->contact->account_name);
03397             SAFE_FREE_STR(item->contact->address1);
03398             SAFE_FREE_STR(item->contact->address1a);
03399             SAFE_FREE_STR(item->contact->address1_desc);
03400             SAFE_FREE_STR(item->contact->address1_transport);
03401             SAFE_FREE_STR(item->contact->address2);
03402             SAFE_FREE_STR(item->contact->address2a);
03403             SAFE_FREE_STR(item->contact->address2_desc);
03404             SAFE_FREE_STR(item->contact->address2_transport);
03405             SAFE_FREE_STR(item->contact->address3);
03406             SAFE_FREE_STR(item->contact->address3a);
03407             SAFE_FREE_STR(item->contact->address3_desc);
03408             SAFE_FREE_STR(item->contact->address3_transport);
03409             SAFE_FREE_STR(item->contact->assistant_name);
03410             SAFE_FREE_STR(item->contact->assistant_phone);
03411             SAFE_FREE_STR(item->contact->billing_information);
03412             SAFE_FREE(item->contact->birthday);
03413             SAFE_FREE_STR(item->contact->business_address);
03414             SAFE_FREE_STR(item->contact->business_city);
03415             SAFE_FREE_STR(item->contact->business_country);
03416             SAFE_FREE_STR(item->contact->business_fax);
03417             SAFE_FREE_STR(item->contact->business_homepage);
03418             SAFE_FREE_STR(item->contact->business_phone);
03419             SAFE_FREE_STR(item->contact->business_phone2);
03420             SAFE_FREE_STR(item->contact->business_po_box);
03421             SAFE_FREE_STR(item->contact->business_postal_code);
03422             SAFE_FREE_STR(item->contact->business_state);
03423             SAFE_FREE_STR(item->contact->business_street);
03424             SAFE_FREE_STR(item->contact->callback_phone);
03425             SAFE_FREE_STR(item->contact->car_phone);
03426             SAFE_FREE_STR(item->contact->company_main_phone);
03427             SAFE_FREE_STR(item->contact->company_name);
03428             SAFE_FREE_STR(item->contact->computer_name);
03429             SAFE_FREE_STR(item->contact->customer_id);
03430             SAFE_FREE_STR(item->contact->def_postal_address);
03431             SAFE_FREE_STR(item->contact->department);
03432             SAFE_FREE_STR(item->contact->display_name_prefix);
03433             SAFE_FREE_STR(item->contact->first_name);
03434             SAFE_FREE_STR(item->contact->followup);
03435             SAFE_FREE_STR(item->contact->free_busy_address);
03436             SAFE_FREE_STR(item->contact->ftp_site);
03437             SAFE_FREE_STR(item->contact->fullname);
03438             SAFE_FREE_STR(item->contact->gov_id);
03439             SAFE_FREE_STR(item->contact->hobbies);
03440             SAFE_FREE_STR(item->contact->home_address);
03441             SAFE_FREE_STR(item->contact->home_city);
03442             SAFE_FREE_STR(item->contact->home_country);
03443             SAFE_FREE_STR(item->contact->home_fax);
03444             SAFE_FREE_STR(item->contact->home_po_box);
03445             SAFE_FREE_STR(item->contact->home_phone);
03446             SAFE_FREE_STR(item->contact->home_phone2);
03447             SAFE_FREE_STR(item->contact->home_postal_code);
03448             SAFE_FREE_STR(item->contact->home_state);
03449             SAFE_FREE_STR(item->contact->home_street);
03450             SAFE_FREE_STR(item->contact->initials);
03451             SAFE_FREE_STR(item->contact->isdn_phone);
03452             SAFE_FREE_STR(item->contact->job_title);
03453             SAFE_FREE_STR(item->contact->keyword);
03454             SAFE_FREE_STR(item->contact->language);
03455             SAFE_FREE_STR(item->contact->location);
03456             SAFE_FREE_STR(item->contact->manager_name);
03457             SAFE_FREE_STR(item->contact->middle_name);
03458             SAFE_FREE_STR(item->contact->mileage);
03459             SAFE_FREE_STR(item->contact->mobile_phone);
03460             SAFE_FREE_STR(item->contact->nickname);
03461             SAFE_FREE_STR(item->contact->office_loc);
03462             SAFE_FREE_STR(item->contact->common_name);
03463             SAFE_FREE_STR(item->contact->org_id);
03464             SAFE_FREE_STR(item->contact->other_address);
03465             SAFE_FREE_STR(item->contact->other_city);
03466             SAFE_FREE_STR(item->contact->other_country);
03467             SAFE_FREE_STR(item->contact->other_phone);
03468             SAFE_FREE_STR(item->contact->other_po_box);
03469             SAFE_FREE_STR(item->contact->other_postal_code);
03470             SAFE_FREE_STR(item->contact->other_state);
03471             SAFE_FREE_STR(item->contact->other_street);
03472             SAFE_FREE_STR(item->contact->pager_phone);
03473             SAFE_FREE_STR(item->contact->personal_homepage);
03474             SAFE_FREE_STR(item->contact->pref_name);
03475             SAFE_FREE_STR(item->contact->primary_fax);
03476             SAFE_FREE_STR(item->contact->primary_phone);
03477             SAFE_FREE_STR(item->contact->profession);
03478             SAFE_FREE_STR(item->contact->radio_phone);
03479             SAFE_FREE_STR(item->contact->spouse_name);
03480             SAFE_FREE_STR(item->contact->suffix);
03481             SAFE_FREE_STR(item->contact->surname);
03482             SAFE_FREE_STR(item->contact->telex);
03483             SAFE_FREE_STR(item->contact->transmittable_display_name);
03484             SAFE_FREE_STR(item->contact->ttytdd_phone);
03485             SAFE_FREE(item->contact->wedding_anniversary);
03486             SAFE_FREE_STR(item->contact->work_address_street);
03487             SAFE_FREE_STR(item->contact->work_address_city);
03488             SAFE_FREE_STR(item->contact->work_address_state);
03489             SAFE_FREE_STR(item->contact->work_address_postalcode);
03490             SAFE_FREE_STR(item->contact->work_address_country);
03491             SAFE_FREE_STR(item->contact->work_address_postofficebox);
03492             free(item->contact);
03493         }
03494 
03495         pst_free_attach(item->attach);
03496 
03497         while (item->extra_fields) {
03498             SAFE_FREE(item->extra_fields->field_name);
03499             SAFE_FREE(item->extra_fields->value);
03500             et = item->extra_fields->next;
03501             free(item->extra_fields);
03502             item->extra_fields = et;
03503         }
03504         if (item->journal) {
03505             SAFE_FREE(item->journal->start);
03506             SAFE_FREE(item->journal->end);
03507             SAFE_FREE_STR(item->journal->type);
03508             free(item->journal);
03509         }
03510         if (item->appointment) {
03511             SAFE_FREE(item->appointment->start);
03512             SAFE_FREE(item->appointment->end);
03513             SAFE_FREE_STR(item->appointment->location);
03514             SAFE_FREE(item->appointment->reminder);
03515             SAFE_FREE_STR(item->appointment->alarm_filename);
03516             SAFE_FREE_STR(item->appointment->timezonestring);
03517             SAFE_FREE_STR(item->appointment->recurrence_description);
03518             SAFE_FREE_BIN(item->appointment->recurrence_data);
03519             SAFE_FREE(item->appointment->recurrence_start);
03520             SAFE_FREE(item->appointment->recurrence_end);
03521             free(item->appointment);
03522         }
03523         SAFE_FREE(item->ascii_type);
03524         SAFE_FREE_STR(item->body_charset);
03525         SAFE_FREE_STR(item->body);
03526         SAFE_FREE_STR(item->subject);
03527         SAFE_FREE_STR(item->comment);
03528         SAFE_FREE(item->create_date);
03529         SAFE_FREE_STR(item->file_as);
03530         SAFE_FREE(item->modify_date);
03531         SAFE_FREE_STR(item->outlook_version);
03532         SAFE_FREE_BIN(item->record_key);
03533         SAFE_FREE_BIN(item->predecessor_change);
03534         free(item);
03535     }
03536     DEBUG_RET();
03537 }
03538 
03539 
03546 static int pst_getBlockOffsetPointer(pst_file *pf, pst_id2_tree *i2_head, pst_subblocks *subblocks, uint32_t offset, pst_block_offset_pointer *p) {
03547     size_t size;
03548     pst_block_offset block_offset;
03549     DEBUG_ENT("pst_getBlockOffsetPointer");
03550     if (p->needfree) free(p->from);
03551     p->from     = NULL;
03552     p->to       = NULL;
03553     p->needfree = 0;
03554     if (!offset) {
03555         // no data
03556         p->from = p->to = NULL;
03557     }
03558     else if ((offset & 0xf) == (uint32_t)0xf) {
03559         // external index reference
03560         DEBUG_WARN(("Found id2 %#x value. Will follow it\n", offset));
03561         size = pst_ff_getID2block(pf, offset, i2_head, &(p->from));
03562         if (size) {
03563             p->to = p->from + size;
03564             p->needfree = 1;
03565         }
03566         else {
03567             if (p->from) {
03568                 DEBUG_WARN(("size zero but non-null pointer\n"));
03569                 free(p->from);
03570             }
03571             p->from = p->to = NULL;
03572         }
03573     }
03574     else {
03575         // internal index reference
03576         size_t subindex  = offset >> 16;
03577         size_t suboffset = offset & 0xffff;
03578         if (subindex < subblocks->subblock_count) {
03579             if (pst_getBlockOffset(subblocks->subs[subindex].buf,
03580                                    subblocks->subs[subindex].read_size,
03581                                    subblocks->subs[subindex].i_offset,
03582                                    suboffset, &block_offset)) {
03583                 p->from = subblocks->subs[subindex].buf + block_offset.from;
03584                 p->to   = subblocks->subs[subindex].buf + block_offset.to;
03585             }
03586         }
03587     }
03588     DEBUG_RET();
03589     return (p->from) ? 0 : 1;
03590 }
03591 
03592 
03594 static int pst_getBlockOffset(char *buf, size_t read_size, uint32_t i_offset, uint32_t offset, pst_block_offset *p) {
03595     uint32_t low = offset & 0xf;
03596     uint32_t of1 = offset >> 4;
03597     DEBUG_ENT("pst_getBlockOffset");
03598     if (!p || !buf || !i_offset || low || (i_offset+2+of1+sizeof(*p) > read_size)) {
03599         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));
03600         DEBUG_RET();
03601         return 0;
03602     }
03603     memcpy(&(p->from), &(buf[(i_offset+2)+of1]), sizeof(p->from));
03604     memcpy(&(p->to), &(buf[(i_offset+2)+of1+sizeof(p->from)]), sizeof(p->to));
03605     LE16_CPU(p->from);
03606     LE16_CPU(p->to);
03607     DEBUG_WARN(("get block offset finds from=%i(%#x), to=%i(%#x)\n", p->from, p->from, p->to, p->to));
03608     if (p->from > p->to) {
03609         DEBUG_WARN(("get block offset from > to\n"));
03610         DEBUG_RET();
03611         return 0;
03612     }
03613     DEBUG_RET();
03614     return 1;
03615 }
03616 
03617 
03619 pst_index_ll* pst_getID(pst_file* pf, uint64_t i_id) {
03620     pst_index_ll *ptr;
03621     DEBUG_ENT("pst_getID");
03622     if (i_id == 0) {
03623         DEBUG_RET();
03624         return NULL;
03625     }
03626 
03627     //if (i_id & 1) DEBUG_INFO(("have odd id bit %#"PRIx64"\n", i_id));
03628     //if (i_id & 2) DEBUG_INFO(("have two id bit %#"PRIx64"\n", i_id));
03629     i_id -= (i_id & 1);
03630 
03631     DEBUG_INFO(("Trying to find %#"PRIx64"\n", i_id));
03632     ptr = pf->i_head;
03633     while (ptr && (ptr->i_id != i_id)) {
03634         ptr = ptr->next;
03635     }
03636     if (ptr) {DEBUG_INFO(("Found Value %#"PRIx64"\n", i_id));            }
03637     else     {DEBUG_INFO(("ERROR: Value %#"PRIx64" not found\n", i_id)); }
03638     DEBUG_RET();
03639     return ptr;
03640 }
03641 
03642 
03643 static pst_id2_tree *pst_getID2(pst_id2_tree *head, uint64_t id2) {
03644     DEBUG_ENT("pst_getID2");
03645     DEBUG_INFO(("looking for id2 = %#"PRIx64"\n", id2));
03646     pst_id2_tree *ptr = head;
03647     while (ptr) {
03648         if (ptr->id2 == id2) break;
03649         if (ptr->child) {
03650             pst_id2_tree *rc = pst_getID2(ptr->child, id2);
03651             if (rc) {
03652                 DEBUG_RET();
03653                 return rc;
03654             }
03655         }
03656         ptr = ptr->next;
03657     }
03658     if (ptr && ptr->id) {
03659         DEBUG_INFO(("Found value %#"PRIx64"\n", ptr->id->i_id));
03660         DEBUG_RET();
03661         return ptr;
03662     }
03663     DEBUG_INFO(("ERROR Not Found\n"));
03664     DEBUG_RET();
03665     return NULL;
03666 }
03667 
03668 
03677 static pst_desc_tree* pst_getDptr(pst_file *pf, uint64_t d_id) {
03678     pst_desc_tree *ptr = pf->d_head;
03679     DEBUG_ENT("pst_getDptr");
03680     while (ptr && (ptr->d_id != d_id)) {
03681         //DEBUG_INFO(("Looking for %#"PRIx64" at node %#"PRIx64" with parent %#"PRIx64"\n", id, ptr->d_id, ptr->parent_d_id));
03682         if (ptr->child) {
03683             ptr = ptr->child;
03684             continue;
03685         }
03686         while (!ptr->next && ptr->parent) {
03687             ptr = ptr->parent;
03688         }
03689         ptr = ptr->next;
03690     }
03691     DEBUG_RET();
03692     return ptr; // will be NULL or record we are looking for
03693 }
03694 
03695 
03696 static void pst_printDptr(pst_file *pf, pst_desc_tree *ptr) {
03697     DEBUG_ENT("pst_printDptr");
03698     while (ptr) {
03699         DEBUG_INFO(("%#"PRIx64" [%i] desc=%#"PRIx64", assoc tree=%#"PRIx64"\n", ptr->d_id, ptr->no_child,
03700                     (ptr->desc       ? ptr->desc->i_id       : (uint64_t)0),
03701                     (ptr->assoc_tree ? ptr->assoc_tree->i_id : (uint64_t)0)));
03702         if (ptr->child) {
03703             pst_printDptr(pf, ptr->child);
03704         }
03705         ptr = ptr->next;
03706     }
03707     DEBUG_RET();
03708 }
03709 
03710 
03711 static void pst_printID2ptr(pst_id2_tree *ptr) {
03712     DEBUG_ENT("pst_printID2ptr");
03713     while (ptr) {
03714         DEBUG_INFO(("%#"PRIx64" id=%#"PRIx64"\n", ptr->id2, (ptr->id ? ptr->id->i_id : (uint64_t)0)));
03715         if (ptr->child) pst_printID2ptr(ptr->child);
03716         ptr = ptr->next;
03717     }
03718     DEBUG_RET();
03719 }
03720 
03721 
03731 static size_t pst_read_block_size(pst_file *pf, int64_t offset, size_t size, char **buf) {
03732     size_t rsize;
03733     DEBUG_ENT("pst_read_block_size");
03734     DEBUG_INFO(("Reading block from %#"PRIx64", %x bytes\n", offset, size));
03735 
03736     if (*buf) {
03737         DEBUG_INFO(("Freeing old memory\n"));
03738         free(*buf);
03739     }
03740     *buf = (char*) pst_malloc(size);
03741 
03742     rsize = pst_getAtPos(pf, offset, *buf, size);
03743     if (rsize != size) {
03744         DEBUG_WARN(("Didn't read all the data. fread returned less [%i instead of %i]\n", rsize, size));
03745         if (feof(pf->fp)) {
03746             DEBUG_WARN(("We tried to read past the end of the file at [offset %#"PRIx64", size %#x]\n", offset, size));
03747         } else if (ferror(pf->fp)) {
03748             DEBUG_WARN(("Error is set on file stream.\n"));
03749         } else {
03750             DEBUG_WARN(("I can't tell why it failed\n"));
03751         }
03752     }
03753 
03754     DEBUG_RET();
03755     return rsize;
03756 }
03757 
03758 
03769 static int pst_decrypt(uint64_t i_id, char *buf, size_t size, unsigned char type) {
03770     size_t x = 0;
03771     unsigned char y;
03772     DEBUG_ENT("pst_decrypt");
03773     if (!buf) {
03774         DEBUG_RET();
03775         return -1;
03776     }
03777 
03778     if (type == PST_COMP_ENCRYPT) {
03779         x = 0;
03780         while (x < size) {
03781             y = (unsigned char)(buf[x]);
03782             buf[x] = (char)comp_enc[y]; // transpose from encrypt array
03783             x++;
03784         }
03785 
03786     } else if (type == PST_ENCRYPT) {
03787         // The following code was based on the information at
03788         // http://www.passcape.com/outlook_passwords.htm
03789         uint16_t salt = (uint16_t) (((i_id & 0x00000000ffff0000) >> 16) ^ (i_id & 0x000000000000ffff));
03790         x = 0;
03791         while (x < size) {
03792             uint8_t losalt = (salt & 0x00ff);
03793             uint8_t hisalt = (salt & 0xff00) >> 8;
03794             y = (unsigned char)buf[x];
03795             y += losalt;
03796             y = comp_high1[y];
03797             y += hisalt;
03798             y = comp_high2[y];
03799             y -= hisalt;
03800             y = comp_enc[y];
03801             y -= losalt;
03802             buf[x] = (char)y;
03803             x++;
03804             salt++;
03805         }
03806 
03807     } else {
03808         DEBUG_WARN(("Unknown encryption: %i. Cannot decrypt\n", type));
03809         DEBUG_RET();
03810         return -1;
03811     }
03812     DEBUG_RET();
03813     return 0;
03814 }
03815 
03816 
03817 static uint64_t pst_getIntAt(pst_file *pf, char *buf) {
03818     uint64_t buf64;
03819     uint32_t buf32;
03820     if (pf->do_read64) {
03821         memcpy(&buf64, buf, sizeof(buf64));
03822         LE64_CPU(buf64);
03823         return buf64;
03824     }
03825     else {
03826         memcpy(&buf32, buf, sizeof(buf32));
03827         LE32_CPU(buf32);
03828         return buf32;
03829     }
03830 }
03831 
03832 
03833 static uint64_t pst_getIntAtPos(pst_file *pf, int64_t pos ) {
03834     uint64_t buf64;
03835     uint32_t buf32;
03836     if (pf->do_read64) {
03837         (void)pst_getAtPos(pf, pos, &buf64, sizeof(buf64));
03838         LE64_CPU(buf64);
03839         return buf64;
03840     }
03841     else {
03842         (void)pst_getAtPos(pf, pos, &buf32, sizeof(buf32));
03843         LE32_CPU(buf32);
03844         return buf32;
03845     }
03846 }
03847 
03857 static size_t pst_getAtPos(pst_file *pf, int64_t pos, void* buf, size_t size) {
03858     size_t rc;
03859     DEBUG_ENT("pst_getAtPos");
03860 //  pst_block_recorder **t = &pf->block_head;
03861 //  pst_block_recorder *p = pf->block_head;
03862 //  while (p && ((p->offset+p->size) <= pos)) {
03863 //      t = &p->next;
03864 //      p = p->next;
03865 //  }
03866 //  if (p && (p->offset <= pos) && (pos < (p->offset+p->size))) {
03867 //      // bump the count
03868 //      p->readcount++;
03869 //  } else {
03870 //      // add a new block
03871 //      pst_block_recorder *tail = *t;
03872 //      p = (pst_block_recorder*)pst_malloc(sizeof(*p));
03873 //      *t = p;
03874 //      p->next      = tail;
03875 //      p->offset    = pos;
03876 //      p->size      = size;
03877 //      p->readcount = 1;
03878 //  }
03879 //  DEBUG_INFO(("pst file old offset %#"PRIx64" old size %#x read count %i offset %#"PRIx64" size %#x\n",
03880 //              p->offset, p->size, p->readcount, pos, size));
03881 
03882     if (fseeko(pf->fp, pos, SEEK_SET) == -1) {
03883         DEBUG_RET();
03884         return 0;
03885     }
03886     rc = fread(buf, (size_t)1, size, pf->fp);
03887     DEBUG_RET();
03888     return rc;
03889 }
03890 
03891 
03900 size_t pst_ff_getIDblock_dec(pst_file *pf, uint64_t i_id, char **buf) {
03901     size_t r;
03902     int noenc = (int)(i_id & 2);   // disable encryption
03903     DEBUG_ENT("pst_ff_getIDblock_dec");
03904     DEBUG_INFO(("for id %#"PRIx64"\n", i_id));
03905     r = pst_ff_getIDblock(pf, i_id, buf);
03906     if ((pf->encryption) && !(noenc)) {
03907         (void)pst_decrypt(i_id, *buf, r, pf->encryption);
03908     }
03909     DEBUG_HEXDUMPC(*buf, r, 16);
03910     DEBUG_RET();
03911     return r;
03912 }
03913 
03914 
03923 static size_t pst_ff_getIDblock(pst_file *pf, uint64_t i_id, char** buf) {
03924     pst_index_ll *rec;
03925     size_t rsize;
03926     DEBUG_ENT("pst_ff_getIDblock");
03927     rec = pst_getID(pf, i_id);
03928     if (!rec) {
03929         DEBUG_INFO(("Cannot find ID %#"PRIx64"\n", i_id));
03930         DEBUG_RET();
03931         return 0;
03932     }
03933     DEBUG_INFO(("id = %#"PRIx64", record size = %#x, offset = %#x\n", i_id, rec->size, rec->offset));
03934     rsize = pst_read_block_size(pf, rec->offset, rec->size, buf);
03935     DEBUG_RET();
03936     return rsize;
03937 }
03938 
03939 
03940 static size_t pst_ff_getID2block(pst_file *pf, uint64_t id2, pst_id2_tree *id2_head, char** buf) {
03941     size_t ret;
03942     pst_id2_tree* ptr;
03943     pst_holder h = {buf, NULL, 0, 0, 0};
03944     DEBUG_ENT("pst_ff_getID2block");
03945     ptr = pst_getID2(id2_head, id2);
03946 
03947     if (!ptr) {
03948         DEBUG_WARN(("Cannot find id2 value %#"PRIx64"\n", id2));
03949         DEBUG_RET();
03950         return 0;
03951     }
03952     ret = pst_ff_getID2data(pf, ptr->id, &h);
03953     DEBUG_RET();
03954     return ret;
03955 }
03956 
03957 
03966 static size_t pst_ff_getID2data(pst_file *pf, pst_index_ll *ptr, pst_holder *h) {
03967     size_t ret;
03968     char *b = NULL;
03969     DEBUG_ENT("pst_ff_getID2data");
03970     if (!(ptr->i_id & 0x02)) {
03971         ret = pst_ff_getIDblock_dec(pf, ptr->i_id, &b);
03972         ret = pst_append_holder(h, (size_t)0, &b, ret);
03973         free(b);
03974     } else {
03975         // here we will assume it is an indirection block that points to others
03976         DEBUG_INFO(("Assuming it is a multi-block record because of it's id %#"PRIx64"\n", ptr->i_id));
03977         ret = pst_ff_compile_ID(pf, ptr->i_id, h, (size_t)0);
03978     }
03979     ret = pst_finish_cleanup_holder(h, ret);
03980     DEBUG_RET();
03981     return ret;
03982 }
03983 
03984 
03994 static size_t pst_ff_compile_ID(pst_file *pf, uint64_t i_id, pst_holder *h, size_t size) {
03995     size_t    z, a;
03996     uint16_t  count, y;
03997     char      *buf3 = NULL;
03998     char      *buf2 = NULL;
03999     char      *b_ptr;
04000     pst_block_hdr  block_hdr;
04001     pst_table3_rec table3_rec;  //for type 3 (0x0101) blocks
04002 
04003     DEBUG_ENT("pst_ff_compile_ID");
04004     a = pst_ff_getIDblock(pf, i_id, &buf3);
04005     if (!a) {
04006         if (buf3) free(buf3);
04007         DEBUG_RET();
04008         return 0;
04009     }
04010     DEBUG_HEXDUMPC(buf3, a, 16);
04011     memcpy(&block_hdr, buf3, sizeof(block_hdr));
04012     LE16_CPU(block_hdr.index_offset);
04013     LE16_CPU(block_hdr.type);
04014     LE32_CPU(block_hdr.offset);
04015     DEBUG_INFO(("block header (index_offset=%#hx, type=%#hx, offset=%#x)\n", block_hdr.index_offset, block_hdr.type, block_hdr.offset));
04016 
04017     count = block_hdr.type;
04018     b_ptr = buf3 + 8;
04019 
04020     // For indirect lookups through a table of i_ids, just recurse back into this
04021     // function, letting it concatenate all the data together, and then return the
04022     // total size of the data.
04023     if (block_hdr.index_offset == (uint16_t)0x0201) { // Indirect lookup (depth 2).
04024         for (y=0; y<count; y++) {
04025             b_ptr += pst_decode_type3(pf, &table3_rec, b_ptr);
04026             size = pst_ff_compile_ID(pf, table3_rec.id, h, size);
04027         }
04028         free(buf3);
04029         DEBUG_RET();
04030         return size;
04031     }
04032 
04033     if (block_hdr.index_offset != (uint16_t)0x0101) { //type 3
04034         DEBUG_WARN(("WARNING: not a type 0x0101 buffer, Treating as normal buffer\n"));
04035         if (pf->encryption) (void)pst_decrypt(i_id, buf3, a, pf->encryption);
04036         size = pst_append_holder(h, size, &buf3, a);
04037         free(buf3);
04038         DEBUG_RET();
04039         return size;
04040     }
04041 
04042     for (y=0; y<count; y++) {
04043         b_ptr += pst_decode_type3(pf, &table3_rec, b_ptr);
04044         z = pst_ff_getIDblock_dec(pf, table3_rec.id, &buf2);
04045         if (!z) {
04046             DEBUG_WARN(("call to getIDblock returned zero %i\n", z));
04047             if (buf2) free(buf2);
04048             free(buf3);
04049             DEBUG_RET();
04050             return z;
04051         }
04052         size = pst_append_holder(h, size, &buf2, z);
04053     }
04054 
04055     free(buf3);
04056     if (buf2) free(buf2);
04057     DEBUG_RET();
04058     return size;
04059 }
04060 
04061 
04070 static size_t pst_append_holder(pst_holder *h, size_t size, char **buf, size_t z) {
04071     char *t;
04072     DEBUG_ENT("pst_append_holder");
04073 
04074     // raw append to a buffer
04075     if (h->buf) {
04076         *(h->buf) = pst_realloc(*(h->buf), size+z+1);
04077         DEBUG_INFO(("appending read data of size %i onto main buffer from pos %i\n", z, size));
04078         memcpy(*(h->buf)+size, *buf, z);
04079 
04080     // base64 encoding to a file
04081     } else if ((h->base64 == 1) && h->fp) {
04082         //
04083         if (h->base64_extra) {
04084             // include any bytes left over from the last encoding
04085             *buf = (char*)pst_realloc(*buf, z+h->base64_extra);
04086             memmove(*buf+h->base64_extra, *buf, z);
04087             memcpy(*buf, h->base64_extra_chars, h->base64_extra);
04088             z += h->base64_extra;
04089         }
04090 
04091         // find out how many bytes will be left over after this encoding and save them
04092         h->base64_extra = z % 3;
04093         if (h->base64_extra) {
04094             z -= h->base64_extra;
04095             memcpy(h->base64_extra_chars, *buf+z, h->base64_extra);
04096         }
04097 
04098         // encode this chunk
04099         t = pst_base64_encode_multiple(*buf, z, &h->base64_line_count);
04100         if (t) {
04101             DEBUG_INFO(("writing %i bytes to file as base64 [%i]. Currently %i\n", z, strlen(t), size));
04102             (void)pst_fwrite(t, (size_t)1, strlen(t), h->fp);
04103             free(t);    // caught by valgrind
04104         }
04105 
04106     // raw append to a file
04107     } else if (h->fp) {
04108         DEBUG_INFO(("writing %i bytes to file. Currently %i\n", z, size));
04109         (void)pst_fwrite(*buf, (size_t)1, z, h->fp);
04110 
04111     // null output
04112     } else {
04113         // h-> does not specify any output
04114     }
04115     DEBUG_RET();
04116     return size+z;
04117 }
04118 
04119 
04126 static size_t pst_finish_cleanup_holder(pst_holder *h, size_t size) {
04127     char *t;
04128     DEBUG_ENT("pst_finish_cleanup_holder");
04129     if ((h->base64 == 1) && h->fp && h->base64_extra) {
04130         // need to encode any bytes left over
04131         t = pst_base64_encode_multiple(h->base64_extra_chars, h->base64_extra, &h->base64_line_count);
04132         if (t) {
04133             (void)pst_fwrite(t, (size_t)1, strlen(t), h->fp);
04134             free(t);    // caught by valgrind
04135         }
04136         size += h->base64_extra;
04137     }
04138     DEBUG_RET();
04139     return size;
04140 }
04141 
04142 
04143 static int pst_stricmp(char *a, char *b) {
04144     // compare strings case-insensitive.
04145     // returns -1 if a < b, 0 if a==b, 1 if a > b
04146     while(*a != '\0' && *b != '\0' && toupper(*a)==toupper(*b)) {
04147         a++; b++;
04148     }
04149     if (toupper(*a) == toupper(*b))
04150         return 0;
04151     else if (toupper(*a) < toupper(*b))
04152         return -1;
04153     else
04154         return 1;
04155 }
04156 
04157 
04158 static int pst_strincmp(char *a, char *b, size_t x) {
04159     // compare upto x chars in string a and b case-insensitively
04160     // returns -1 if a < b, 0 if a==b, 1 if a > b
04161     size_t y = 0;
04162     while (*a != '\0' && *b != '\0' && y < x && toupper(*a)==toupper(*b)) {
04163         a++; b++; y++;
04164     }
04165     // if we have reached the end of either string, or a and b still match
04166     if (*a == '\0' || *b == '\0' || toupper(*a)==toupper(*b))
04167         return 0;
04168     else if (toupper(*a) < toupper(*b))
04169         return -1;
04170     else
04171         return 1;
04172 }
04173 
04174 
04175 size_t pst_fwrite(const void* ptr, size_t size, size_t nmemb, FILE *stream) {
04176     size_t r;
04177     if (ptr)
04178         r = fwrite(ptr, size, nmemb, stream);
04179     else {
04180         r = 0;
04181         DEBUG_ENT("pst_fwrite");
04182         DEBUG_WARN(("An attempt to write a NULL Pointer was made\n"));
04183         DEBUG_RET();
04184     }
04185     return r;
04186 }
04187 
04188 
04189 static char* pst_wide_to_single(char *wt, size_t size) {
04190     // returns the first byte of each wide char. the size is the number of bytes in source
04191     char *x, *y;
04192     DEBUG_ENT("pst_wide_to_single");
04193     x = pst_malloc((size/2)+1);
04194     y = x;
04195     while (size != 0 && *wt != '\0') {
04196         *y = *wt;
04197         wt+=2;
04198         size -= 2;
04199         y++;
04200     }
04201     *y = '\0';
04202     DEBUG_RET();
04203     return x;
04204 }
04205 
04206 
04207 char* pst_rfc2426_escape(char* str, char **buf, size_t* buflen) {
04208     //static char*  buf    = NULL;
04209     //static size_t buflen = 0;
04210     char *ret, *a, *b;
04211     size_t x = 0;
04212     int y, z;
04213     if (!str) return NULL;
04214     DEBUG_ENT("rfc2426_escape");
04215     // calculate space required to escape all the following characters
04216     y = pst_chr_count(str, ',')
04217       + pst_chr_count(str, '\\')
04218       + pst_chr_count(str, ';')
04219       + pst_chr_count(str, '\n');
04220     z = pst_chr_count(str, '\r');
04221     if (y == 0 && z == 0)
04222         // there isn't any extra space required
04223         ret = str;
04224     else {
04225         x = strlen(str) + y - z + 1; // don't forget room for the NUL
04226         if (x > *buflen) {
04227             *buf = (char*)pst_realloc(*buf, x);
04228             *buflen = x;
04229         }
04230         a = str;
04231         b = *buf;
04232         while (*a != '\0') {
04233             switch (*a) {
04234             case ',' :
04235             case '\\':
04236             case ';' :
04237                 *(b++) = '\\';
04238                 *b = *a;
04239                 break;
04240             case '\n':  // newlines are encoded as "\n"
04241                 *(b++) = '\\';
04242                 *b = 'n';
04243                 break;
04244             case '\r':  // skip cr
04245                 b--;
04246                 break;
04247             default:
04248                 *b=*a;
04249             }
04250             b++;
04251             a++;
04252         }
04253         *b = '\0'; // NUL-terminate the string (buf)
04254         ret = *buf;
04255     }
04256     DEBUG_RET();
04257     return ret;
04258 }
04259 
04260 
04261 static int pst_chr_count(char *str, char x) {
04262     int r = 0;
04263     while (*str) {
04264         if (*str == x) r++;
04265         str++;
04266     }
04267     return r;
04268 }
04269 
04270 
04271 char* pst_rfc2425_datetime_format(const FILETIME* ft, int buflen, char* result) {
04272     struct tm stm;
04273     DEBUG_ENT("rfc2425_datetime_format");
04274     pst_fileTimeToStructTM(ft, &stm);
04275     if (strftime(result, buflen, "%Y-%m-%dT%H:%M:%SZ", &stm)==0) {
04276         DEBUG_INFO(("Problem occured formatting date\n"));
04277     }
04278     DEBUG_RET();
04279     return result;
04280 }
04281 
04282 
04283 char* pst_rfc2445_datetime_format(const FILETIME* ft, int buflen, char* result) {
04284     struct tm stm;
04285     DEBUG_ENT("rfc2445_datetime_format");
04286     pst_fileTimeToStructTM(ft, &stm);
04287     if (strftime(result, buflen, "%Y%m%dT%H%M%SZ", &stm)==0) {
04288         DEBUG_INFO(("Problem occured formatting date\n"));
04289     }
04290     DEBUG_RET();
04291     return result;
04292 }
04293 
04294 
04295 char* pst_rfc2445_datetime_format_now(int buflen, char* result) {
04296     struct tm stm;
04297     time_t t = time(NULL);
04298     DEBUG_ENT("rfc2445_datetime_format_now");
04299     gmtime_r(&t, &stm);
04300     if (strftime(result, buflen, "%Y%m%dT%H%M%SZ", &stm)==0) {
04301         DEBUG_INFO(("Problem occured formatting date\n"));
04302     }
04303     DEBUG_RET();
04304     return result;
04305 }
04306 
04307 
04316 static const char* codepage(int cp, int buflen, char* result);
04317 static const char* codepage(int cp, int buflen, char* result) {
04318     switch (cp) {
04319         case   932 : return "iso-2022-jp";
04320         case   936 : return "gb2313";
04321         case   950 : return "big5";
04322         case  1200 : return "ucs-2le";
04323         case  1201 : return "ucs-2be";
04324         case 20127 : return "us-ascii";
04325         case 20269 : return "iso-6937";
04326         case 20865 : return "iso-8859-15";
04327         case 20866 : return "koi8-r";
04328         case 21866 : return "koi8-u";
04329         case 28591 : return "iso-8859-1";
04330         case 28592 : return "iso-8859-2";
04331         case 28595 : return "iso-8859-5";
04332         case 28596 : return "iso-8859-6";
04333         case 28597 : return "iso-8859-7";
04334         case 28598 : return "iso-8859-8";
04335         case 28599 : return "iso-8859-9";
04336         case 28600 : return "iso-8859-10";
04337         case 28601 : return "iso-8859-11";
04338         case 28602 : return "iso-8859-12";
04339         case 28603 : return "iso-8859-13";
04340         case 28604 : return "iso-8859-14";
04341         case 28605 : return "iso-8859-15";
04342         case 28606 : return "iso-8859-16";
04343         case 50220 : return "iso-2022-jp";
04344         case 50221 : return "csiso2022jp";
04345         case 51932 : return "euc-jp";
04346         case 51949 : return "euc-kr";
04347         case 65000 : return "utf-7";
04348         case 65001 : return "utf-8";
04349         default :
04350             snprintf(result, buflen, "windows-%d", cp);
04351             return result;
04352     }
04353     return NULL;
04354 }
04355 
04356 
04365 const char*    pst_default_charset(pst_item *item, int buflen, char* result) {
04366     return (item->body_charset.str)         ? item->body_charset.str :
04367            (item->message_codepage)         ? codepage(item->message_codepage, buflen, result) :
04368            (item->internet_cpid)            ? codepage(item->internet_cpid, buflen, result) :
04369            (item->pf && item->pf->charset)  ? item->pf->charset :
04370            "iso-8859-1";
04371 }
04372 
04373 
04378 void pst_rfc2231(pst_string *str) {
04379     int needs = 0;
04380     const int8_t *x = (int8_t *)str->str;
04381     while (*x) {
04382         if (*x <= 32) needs++;
04383         x++;
04384     }
04385     int n = strlen(str->str) + 2*needs + 15;
04386     char *buffer = pst_malloc(n);
04387     strcpy(buffer, "utf-8''");
04388     x = (int8_t *)str->str;
04389     const uint8_t *y = (uint8_t *)str->str;
04390     uint8_t *z = (uint8_t *)buffer;
04391     z += strlen(buffer);    // skip the utf8 prefix
04392     while (*y) {
04393         if (*x <= 32) {
04394             *(z++) = (uint8_t)'%';
04395             snprintf(z, 3, "%2x", *y);
04396             z += 2;
04397         }
04398         else {
04399             *(z++) = *y;
04400         }
04401         x++;
04402         y++;
04403     }
04404     *z = '\0';
04405     free(str->str);
04406     str->str = buffer;
04407 }
04408 
04409 
04416 void pst_rfc2047(pst_item *item, pst_string *str, int needs_quote) {
04417     int has_space = 0;
04418     int needs_coding = 0;
04419     pst_convert_utf8(item, str);
04420     const int8_t *x = (int8_t *)str->str;
04421     while (*x) {
04422         if (*x == 32) has_space = 1;
04423         if (*x < 32)  needs_coding = 1;
04424         x++;
04425     }
04426     if (needs_coding) {
04427         char *enc = pst_base64_encode_single(str->str, strlen(str->str));
04428         free(str->str);
04429         int n = strlen(enc) + 20;
04430         str->str = pst_malloc(n);
04431         snprintf(str->str, n, "=?utf-8?B?%s?=", enc);
04432         free(enc);
04433     }
04434     else if (has_space && needs_quote) {
04435         int n = strlen(str->str) + 10;
04436         char *buffer = pst_malloc(n);
04437         snprintf(buffer, n, "\"%s\"", str->str);
04438         free(str->str);
04439         str->str = buffer;
04440     }
04441 }
04442 
04443 
04449 void pst_convert_utf8_null(pst_item *item, pst_string *str) {
04450     if (!str->str) return;
04451     pst_convert_utf8(item, str);
04452 }
04453 
04454 
04460 void pst_convert_utf8(pst_item *item, pst_string *str) {
04461     DEBUG_ENT("pst_convert_utf8");
04462     char buffer[30];
04463     if (str->is_utf8) {
04464         DEBUG_WARN(("Already utf8\n"));
04465         DEBUG_RET();
04466         return;
04467     }
04468     if (!str->str) {
04469         str->str = strdup("");
04470         DEBUG_WARN(("null to empty string\n"));
04471         DEBUG_RET();
04472         return;
04473     }
04474     const char *charset = pst_default_charset(item, sizeof(buffer), buffer);
04475     DEBUG_WARN(("default charset is %s\n", charset));
04476     if (!strcasecmp("utf-8", charset)) {
04477         DEBUG_RET();
04478         return;
04479     }
04480     pst_vbuf *newer = pst_vballoc(2);
04481     size_t rc = pst_vb_8bit2utf8(newer, str->str, strlen(str->str) + 1, charset);
04482     if (rc == (size_t)-1) {
04483         free(newer->b);
04484         DEBUG_WARN(("Failed to convert %s to utf-8 - %s\n", charset, str->str));
04485     }
04486     else {
04487         free(str->str);
04488         str->str = newer->b;
04489         str->is_utf8 = 1;
04490     }
04491     free(newer);
04492     DEBUG_RET();
04493 }
04494 
04495 
04500 pst_recurrence* pst_convert_recurrence(pst_item_appointment* appt)
04501 {
04502     const int bias = 30 * 24 * 60;  // minutes in 30 days
04503     int m[4] = {3,4,4,5};
04504     pst_recurrence *r = pst_malloc(sizeof(pst_recurrence));
04505     memset(r, 0, sizeof(pst_recurrence));
04506     size_t s = appt->recurrence_data.size;
04507     size_t i = 0;
04508     char*  p = appt->recurrence_data.data;
04509     if (p) {
04510         if (i+4 <= s) { r->signature        = PST_LE_GET_UINT32(p+i);        i += 4; }
04511         if (i   <= s) { r->type             = PST_LE_GET_UINT8(p+i) - 0x0a;  i += 2; }
04512         if (i+4 <= s) { r->sub_type         = PST_LE_GET_UINT32(p+i);        i += 4; }
04513         if (r->sub_type <= 3) {
04514             int n = m[r->sub_type]; // number of parms for this sub_type
04515             int j = 0;
04516             for (j=0; j<n; j++) {
04517                 if (i+4 <= s) { *(&r->parm1 + j) = PST_LE_GET_UINT32(p+i);   i += 4; }
04518             }
04519         }
04520         if (i   <= s) { r->termination      = PST_LE_GET_UINT8(p+i) - 0x21;  i += 4; }
04521         if (i+4 <= s) { r->count            = PST_LE_GET_UINT32(p+i);        i += 4; }
04522         if (r->termination == 2) r->count = 0;
04523         switch (r->type) {
04524             case 0: // daily
04525                 if (r->sub_type == 0) {
04526                     // simple daily
04527                     r->interval = r->parm2 / (24 * 60); // was minutes between recurrences
04528                 }
04529                 else {
04530                     // daily every weekday, subset of weekly
04531                     r->interval  = 1;
04532                     r->bydaymask = r->parm4;
04533                 }
04534                 break;
04535             case 1: // weekly
04536                 r->interval  = r->parm2;
04537                 r->bydaymask = r->parm4;
04538                 break;
04539             case 2: // monthly
04540                 r->interval = r->parm2;
04541                 if (r->sub_type == 2) {
04542                     // monthly on day d
04543                     r->dayofmonth = r->parm4;
04544                 }
04545                 else {
04546                     // monthly on 2nd tuesday
04547                     r->bydaymask = r->parm4;
04548                     r->position  = r->parm5;
04549                 }
04550                 break;
04551             case 3: // yearly
04552                 r->interval    = 1;
04553                 r->monthofyear = ((r->parm1 + bias/2) / bias) + 1;
04554                 if (r->sub_type == 2) {
04555                     // yearly on day d of month m
04556                     r->dayofmonth  = r->parm4;
04557                 }
04558                 else {
04559                     // yearly on 2nd tuesday of month m
04560                     r->bydaymask = r->parm4;
04561                     r->position  = r->parm5;
04562                 }
04563                 break;
04564             default:
04565                 break;
04566         }
04567     }
04568     return r;
04569 }
04570 
04571 
04575 void pst_free_recurrence(pst_recurrence* r)
04576 {
04577     if (r) free(r);
04578 }

Generated on 27 Dec 2012 for 'LibPst' by  doxygen 1.6.1