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

Generated on 26 Mar 2020 for 'LibPst' by  doxygen 1.6.1