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

Generated on 9 Aug 2012 for 'LibPst' by  doxygen 1.6.1