libpst.c

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

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