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

libpst.c

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

Generated on Fri Dec 11 08:46:43 2009 for 'LibPst' by  doxygen 1.3.9.1