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

Generated on 21 Jul 2017 for 'LibPst' by  doxygen 1.6.1