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             if (item->flags & PST_FLAG_HAS_ATTACHMENT) {
01308                 // Only report an error if we expected to see an attachment table and didn't.
01309                 DEBUG_WARN(("ERROR error processing main attachment record\n"));
01310             }
01311             if (!m_head) pst_free_id2(id2_head);
01312             DEBUG_RET();
01313             return item;
01314         }
01315         for (x=0; x < list->count_objects; x++) {
01316             attach = (pst_item_attach*) pst_malloc(sizeof(pst_item_attach));
01317             memset(attach, 0, sizeof(pst_item_attach));
01318             attach->next = item->attach;
01319             item->attach = attach;
01320         }
01321         if (pst_process(id2_ptr->id->i_id, list, item, item->attach)) {
01322             DEBUG_WARN(("ERROR pst_process() failed with attachments\n"));
01323             pst_freeItem(item);
01324             pst_free_list(list);
01325             if (!m_head) pst_free_id2(id2_head);
01326             DEBUG_RET();
01327             return NULL;
01328         }
01329         pst_free_list(list);
01330 
01331         // now we will have initial information of each attachment stored in item->attach...
01332         // we must now read the secondary record for each based on the id2_val associated with
01333         // each attachment
01334         for (attach = item->attach; attach; attach = attach->next) {
01335             DEBUG_WARN(("initial attachment id2 %#"PRIx64"\n", attach->id2_val));
01336             if ((id2_ptr = pst_getID2(id2_head, attach->id2_val))) {
01337                 DEBUG_WARN(("initial attachment id2 found id %#"PRIx64"\n", id2_ptr->id->i_id));
01338                 // id2_ptr is a record describing the attachment
01339                 // we pass NULL instead of id2_head cause we don't want it to
01340                 // load all the extra stuff here.
01341                 list = pst_parse_block(pf, id2_ptr->id->i_id, NULL);
01342                 if (!list) {
01343                     DEBUG_WARN(("ERROR error processing an attachment record\n"));
01344                     continue;
01345                 }
01346                 if (list->count_objects > 1) {
01347                     DEBUG_WARN(("ERROR probably fatal, list count array will overrun attach structure.\n"));
01348                 }
01349                 // reprocess the same attachment list against new data
01350                 // this might update attach->id2_val
01351                 if (pst_process(id2_ptr->id->i_id, list, item, attach)) {
01352                     DEBUG_WARN(("ERROR pst_process() failed with an attachment\n"));
01353                     pst_free_list(list);
01354                     continue;
01355                 }
01356                 pst_free_list(list);
01357                 // As per 2.4.6.2 in the spec, the attachment data is stored as a child of the
01358                 // attachment object, so we pass in id2_ptr as the head to search from.
01359                 id2_ptr = pst_getID2(id2_ptr, attach->id2_val);
01360                 if (id2_ptr) {
01361                     DEBUG_WARN(("second pass attachment updating id2 %#"PRIx64" found i_id %#"PRIx64"\n", attach->id2_val, id2_ptr->id->i_id));
01362                     // i_id has been updated to the datablock containing the attachment data
01363                     attach->i_id     = id2_ptr->id->i_id;
01364                     attach->id2_head = deep_copy(id2_ptr->child);
01365                 } else {
01366                     DEBUG_WARN(("have not located the correct value for the attachment [%#"PRIx64"]\n", attach->id2_val));
01367                 }
01368             } else {
01369                 DEBUG_WARN(("ERROR cannot locate id2 value %#"PRIx64"\n", attach->id2_val));
01370                 attach->id2_val = 0;    // suppress this missing attachment
01371             }
01372         }
01373     }
01374 
01375     if (!m_head) pst_free_id2(id2_head);
01376     DEBUG_RET();
01377     return item;
01378 }
01379 
01380 
01381 static void freeall(pst_subblocks *subs, pst_block_offset_pointer *p1,
01382                                          pst_block_offset_pointer *p2,
01383                                          pst_block_offset_pointer *p3,
01384                                          pst_block_offset_pointer *p4,
01385                                          pst_block_offset_pointer *p5,
01386                                          pst_block_offset_pointer *p6,
01387                                          pst_block_offset_pointer *p7);
01388 static void freeall(pst_subblocks *subs, pst_block_offset_pointer *p1,
01389                                          pst_block_offset_pointer *p2,
01390                                          pst_block_offset_pointer *p3,
01391                                          pst_block_offset_pointer *p4,
01392                                          pst_block_offset_pointer *p5,
01393                                          pst_block_offset_pointer *p6,
01394                                          pst_block_offset_pointer *p7) {
01395     size_t i;
01396     for (i=0; i<subs->subblock_count; i++) {
01397         if (subs->subs[i].buf) free(subs->subs[i].buf);
01398     }
01399     free(subs->subs);
01400     if (p1->needfree) free(p1->from);
01401     if (p2->needfree) free(p2->from);
01402     if (p3->needfree) free(p3->from);
01403     if (p4->needfree) free(p4->from);
01404     if (p5->needfree) free(p5->from);
01405     if (p6->needfree) free(p6->from);
01406     if (p7->needfree) free(p7->from);
01407 }
01408 
01409 
01415 static pst_mapi_object* pst_parse_block(pst_file *pf, uint64_t block_id, pst_id2_tree *i2_head) {
01416     pst_mapi_object *mo_head = NULL;
01417     char  *buf       = NULL;
01418     size_t read_size = 0;
01419     pst_subblocks  subblocks;
01420     pst_mapi_object *mo_ptr = NULL;
01421     pst_block_offset_pointer block_offset1;
01422     pst_block_offset_pointer block_offset2;
01423     pst_block_offset_pointer block_offset3;
01424     pst_block_offset_pointer block_offset4;
01425     pst_block_offset_pointer block_offset5;
01426     pst_block_offset_pointer block_offset6;
01427     pst_block_offset_pointer block_offset7;
01428     int32_t  x;
01429     int32_t  num_mapi_objects;
01430     int32_t  count_mapi_objects;
01431     int32_t  num_mapi_elements;
01432     int32_t  count_mapi_elements;
01433     int      block_type;
01434     uint32_t rec_size = 0;
01435     char*    list_start;
01436     char*    fr_ptr;
01437     char*    to_ptr;
01438     char*    ind2_end = NULL;
01439     char*    ind2_ptr = NULL;
01440     pst_x_attrib_ll *mapptr;
01441     pst_block_hdr    block_hdr;
01442     pst_table3_rec   table3_rec;  //for type 3 (0x0101) blocks
01443 
01444     struct {
01445         unsigned char seven_c;
01446         unsigned char item_count;
01447         uint16_t u1;
01448         uint16_t u2;
01449         uint16_t u3;
01450         uint16_t rec_size;
01451         uint32_t b_five_offset;
01452         uint32_t ind2_offset;
01453         uint16_t u7;
01454         uint16_t u8;
01455     } seven_c_blk;
01456 
01457     struct _type_d_rec {
01458         uint32_t id;
01459         uint32_t u1;
01460     } * type_d_rec;
01461 
01462     struct {
01463         uint16_t type;
01464         uint16_t ref_type;
01465         uint32_t value;
01466     } table_rec;    //for type 1 (0xBCEC) blocks
01467 
01468     struct {
01469         uint16_t ref_type;
01470         uint16_t type;
01471         uint16_t ind2_off;
01472         uint8_t  size;
01473         uint8_t  slot;
01474     } table2_rec;   //for type 2 (0x7CEC) blocks
01475 
01476     DEBUG_ENT("pst_parse_block");
01477     if ((read_size = pst_ff_getIDblock_dec(pf, block_id, &buf)) == 0) {
01478         DEBUG_WARN(("Error reading block id %#"PRIx64"\n", block_id));
01479         if (buf) free (buf);
01480         DEBUG_RET();
01481         return NULL;
01482     }
01483 
01484     block_offset1.needfree = 0;
01485     block_offset2.needfree = 0;
01486     block_offset3.needfree = 0;
01487     block_offset4.needfree = 0;
01488     block_offset5.needfree = 0;
01489     block_offset6.needfree = 0;
01490     block_offset7.needfree = 0;
01491 
01492     memcpy(&block_hdr, buf, sizeof(block_hdr));
01493     LE16_CPU(block_hdr.index_offset);
01494     LE16_CPU(block_hdr.type);
01495     LE32_CPU(block_hdr.offset);
01496     DEBUG_INFO(("block header (index_offset=%#hx, type=%#hx, offset=%#hx)\n", block_hdr.index_offset, block_hdr.type, block_hdr.offset));
01497 
01498     if (block_hdr.index_offset == (uint16_t)0x0101) { //type 3
01499         size_t i;
01500         char *b_ptr = buf + 8;
01501         subblocks.subblock_count = block_hdr.type;
01502         subblocks.subs = malloc(sizeof(pst_subblock) * subblocks.subblock_count);
01503         for (i=0; i<subblocks.subblock_count; i++) {
01504             b_ptr += pst_decode_type3(pf, &table3_rec, b_ptr);
01505             subblocks.subs[i].buf       = NULL;
01506             subblocks.subs[i].read_size = pst_ff_getIDblock_dec(pf, table3_rec.id, &subblocks.subs[i].buf);
01507             if (subblocks.subs[i].buf) {
01508                 memcpy(&block_hdr, subblocks.subs[i].buf, sizeof(block_hdr));
01509                 LE16_CPU(block_hdr.index_offset);
01510                 subblocks.subs[i].i_offset = block_hdr.index_offset;
01511             }
01512             else {
01513                 subblocks.subs[i].read_size = 0;
01514                 subblocks.subs[i].i_offset  = 0;
01515             }
01516         }
01517         free(buf);
01518         memcpy(&block_hdr, subblocks.subs[0].buf, sizeof(block_hdr));
01519         LE16_CPU(block_hdr.index_offset);
01520         LE16_CPU(block_hdr.type);
01521         LE32_CPU(block_hdr.offset);
01522         DEBUG_INFO(("block header (index_offset=%#hx, type=%#hx, offset=%#hx)\n", block_hdr.index_offset, block_hdr.type, block_hdr.offset));
01523     }
01524     else {
01525         // setup the subblock descriptors, but we only have one block
01526         subblocks.subblock_count = (size_t)1;
01527         subblocks.subs = malloc(sizeof(pst_subblock));
01528         subblocks.subs[0].buf       = buf;
01529         subblocks.subs[0].read_size = read_size;
01530         subblocks.subs[0].i_offset  = block_hdr.index_offset;
01531     }
01532 
01533     if (block_hdr.type == (uint16_t)0xBCEC) { //type 1
01534         block_type = 1;
01535 
01536         if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, block_hdr.offset, &block_offset1)) {
01537             DEBUG_WARN(("internal error (bc.b5 offset %#x) in reading block id %#"PRIx64"\n", block_hdr.offset, block_id));
01538             freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01539             DEBUG_RET();
01540             return NULL;
01541         }
01542         memcpy(&table_rec, block_offset1.from, sizeof(table_rec));
01543         LE16_CPU(table_rec.type);
01544         LE16_CPU(table_rec.ref_type);
01545         LE32_CPU(table_rec.value);
01546         DEBUG_INFO(("table_rec (type=%#hx, ref_type=%#hx, value=%#x)\n", table_rec.type, table_rec.ref_type, table_rec.value));
01547 
01548         if ((table_rec.type != (uint16_t)0x02B5) || (table_rec.ref_type != 6)) {
01549             DEBUG_WARN(("Unknown second block constant - %#hx %#hx for id %#"PRIx64"\n", table_rec.type, table_rec.ref_type, block_id));
01550             freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01551             DEBUG_RET();
01552             return NULL;
01553         }
01554 
01555         if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, table_rec.value, &block_offset2)) {
01556             DEBUG_WARN(("internal error (bc.b5.desc offset #x) in reading block id %#"PRIx64"\n", table_rec.value, block_id));
01557             freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01558             DEBUG_RET();
01559             return NULL;
01560         }
01561         list_start = block_offset2.from;
01562         to_ptr     = block_offset2.to;
01563         num_mapi_elements = (to_ptr - list_start)/sizeof(table_rec);
01564         num_mapi_objects  = 1; // only going to be one object in these blocks
01565     }
01566     else if (block_hdr.type == (uint16_t)0x7CEC) { //type 2
01567         block_type = 2;
01568 
01569         if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, block_hdr.offset, &block_offset3)) {
01570             DEBUG_WARN(("internal error (7c.7c offset %#x) in reading block id %#"PRIx64"\n", block_hdr.offset, block_id));
01571             freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01572             DEBUG_RET();
01573             return NULL;
01574         }
01575         fr_ptr = block_offset3.from; //now got pointer to "7C block"
01576         memset(&seven_c_blk, 0, sizeof(seven_c_blk));
01577         memcpy(&seven_c_blk, fr_ptr, sizeof(seven_c_blk));
01578         LE16_CPU(seven_c_blk.u1);
01579         LE16_CPU(seven_c_blk.u2);
01580         LE16_CPU(seven_c_blk.u3);
01581         LE16_CPU(seven_c_blk.rec_size);
01582         LE32_CPU(seven_c_blk.b_five_offset);
01583         LE32_CPU(seven_c_blk.ind2_offset);
01584         LE16_CPU(seven_c_blk.u7);
01585         LE16_CPU(seven_c_blk.u8);
01586 
01587         list_start = fr_ptr + sizeof(seven_c_blk); // the list of item numbers start after this record
01588 
01589         if (seven_c_blk.seven_c != 0x7C) { // this would mean it isn't a 7C block!
01590             DEBUG_WARN(("Error. There isn't a 7C where I want to see 7C!\n"));
01591             freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01592             DEBUG_RET();
01593             return NULL;
01594         }
01595 
01596         rec_size = seven_c_blk.rec_size;
01597         num_mapi_elements = (int32_t)(unsigned)seven_c_blk.item_count;
01598 
01599         if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, seven_c_blk.b_five_offset, &block_offset4)) {
01600             DEBUG_WARN(("internal error (7c.b5 offset %#x) in reading block id %#"PRIx64"\n", seven_c_blk.b_five_offset, block_id));
01601             freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01602             DEBUG_RET();
01603             return NULL;
01604         }
01605         memcpy(&table_rec, block_offset4.from, sizeof(table_rec));
01606         LE16_CPU(table_rec.type);
01607         LE16_CPU(table_rec.ref_type);
01608         LE32_CPU(table_rec.value);
01609         DEBUG_INFO(("table_rec (type=%#hx, ref_type=%#hx, value=%#x)\n", table_rec.type, table_rec.ref_type, table_rec.value));
01610 
01611         if (table_rec.type != (uint16_t)0x04B5) { // different constant than a type 1 record
01612             DEBUG_WARN(("Unknown second block constant - %#hx for id %#"PRIx64"\n", table_rec.type, block_id));
01613             freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01614             DEBUG_RET();
01615             return NULL;
01616         }
01617 
01618         if (table_rec.value > 0) {
01619             if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, table_rec.value, &block_offset5)) {
01620                 DEBUG_WARN(("internal error (7c.b5.desc offset %#x) in reading block id %#"PRIx64"\n", table_rec.value, block_id));
01621                 freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01622                 DEBUG_RET();
01623                 return NULL;
01624             }
01625 
01626             // this will give the number of records in this block
01627             num_mapi_objects = (block_offset5.to - block_offset5.from) / (4 + table_rec.ref_type);
01628 
01629             if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, seven_c_blk.ind2_offset, &block_offset6)) {
01630                 DEBUG_WARN(("internal error (7c.ind2 offset %#x) in reading block id %#"PRIx64"\n", seven_c_blk.ind2_offset, block_id));
01631                 freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01632                 DEBUG_RET();
01633                 return NULL;
01634             }
01635             ind2_ptr = block_offset6.from;
01636             ind2_end = block_offset6.to;
01637         }
01638         else {
01639             num_mapi_objects = 0;
01640         }
01641         DEBUG_INFO(("7cec block index2 pointer %#x and end %#x\n", ind2_ptr, ind2_end));
01642     }
01643     else {
01644         DEBUG_WARN(("ERROR: Unknown block constant - %#hx for id %#"PRIx64"\n", block_hdr.type, block_id));
01645         freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01646         DEBUG_RET();
01647         return NULL;
01648     }
01649 
01650     DEBUG_INFO(("found %i mapi objects each with %i mapi elements\n", num_mapi_objects, num_mapi_elements));
01651     for (count_mapi_objects=0; count_mapi_objects<num_mapi_objects; count_mapi_objects++) {
01652         // put another mapi object on the linked list
01653         mo_ptr = (pst_mapi_object*) pst_malloc(sizeof(pst_mapi_object));
01654         memset(mo_ptr, 0, sizeof(pst_mapi_object));
01655         mo_ptr->next = mo_head;
01656         mo_head = mo_ptr;
01657         // allocate the array of mapi elements
01658         mo_ptr->elements        = (pst_mapi_element**) pst_malloc(sizeof(pst_mapi_element)*num_mapi_elements);
01659         mo_ptr->count_elements  = num_mapi_elements;
01660         mo_ptr->orig_count      = num_mapi_elements;
01661         mo_ptr->count_objects   = (int32_t)num_mapi_objects; // each record will have a record of the total number of records
01662         for (x=0; x<num_mapi_elements; x++) mo_ptr->elements[x] = NULL;
01663 
01664         DEBUG_INFO(("going to read %i mapi elements for mapi object %i\n", num_mapi_elements, count_mapi_objects));
01665 
01666         fr_ptr = list_start;    // initialize fr_ptr to the start of the list.
01667         x = 0;                  // x almost tracks count_mapi_elements, but see 'continue' statement below
01668         for (count_mapi_elements=0; count_mapi_elements<num_mapi_elements; count_mapi_elements++) { //we will increase fr_ptr as we progress through index
01669             char* value_pointer = NULL;     // needed for block type 2 with values larger than 4 bytes
01670             size_t value_size = 0;
01671             if (block_type == 1) {
01672                 memcpy(&table_rec, fr_ptr, sizeof(table_rec));
01673                 LE16_CPU(table_rec.type);
01674                 LE16_CPU(table_rec.ref_type);
01675                 //LE32_CPU(table_rec.value);    // done later, some may be order invariant
01676                 fr_ptr += sizeof(table_rec);
01677             } else if (block_type == 2) {
01678                 // we will copy the table2_rec values into a table_rec record so that we can keep the rest of the code
01679                 memcpy(&table2_rec, fr_ptr, sizeof(table2_rec));
01680                 LE16_CPU(table2_rec.ref_type);
01681                 LE16_CPU(table2_rec.type);
01682                 LE16_CPU(table2_rec.ind2_off);
01683                 DEBUG_INFO(("reading element %i (type=%#x, ref_type=%#x, offset=%#x, size=%#x)\n",
01684                     x, table2_rec.type, table2_rec.ref_type, table2_rec.ind2_off, table2_rec.size));
01685 
01686                 // table_rec and table2_rec are arranged differently, so assign the values across
01687                 table_rec.type     = table2_rec.type;
01688                 table_rec.ref_type = table2_rec.ref_type;
01689                 table_rec.value    = 0;
01690                 if ((ind2_end - ind2_ptr) >= (int)(table2_rec.ind2_off + table2_rec.size)) {
01691                     size_t n = table2_rec.size;
01692                     size_t m = sizeof(table_rec.value);
01693                     if (n <= m) {
01694                         memcpy(&table_rec.value, ind2_ptr + table2_rec.ind2_off, n);
01695                     }
01696                     else {
01697                         value_pointer = ind2_ptr + table2_rec.ind2_off;
01698                         value_size    = n;
01699                     }
01700                     //LE32_CPU(table_rec.value);    // done later, some may be order invariant
01701                 }
01702                 else {
01703                     DEBUG_WARN (("Trying to read outside buffer, buffer size %#x, offset %#x, data size %#x\n",
01704                                 read_size, ind2_end-ind2_ptr+table2_rec.ind2_off, table2_rec.size));
01705                 }
01706                 fr_ptr += sizeof(table2_rec);
01707             } else {
01708                 DEBUG_WARN(("Missing code for block_type %i\n", block_type));
01709                 freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01710                 pst_free_list(mo_head);
01711                 DEBUG_RET();
01712                 return NULL;
01713             }
01714             DEBUG_INFO(("reading element %i (type=%#x, ref_type=%#x, value=%#x)\n",
01715                 x, table_rec.type, table_rec.ref_type, table_rec.value));
01716 
01717             if (!mo_ptr->elements[x]) {
01718                 mo_ptr->elements[x] = (pst_mapi_element*) pst_malloc(sizeof(pst_mapi_element));
01719             }
01720             memset(mo_ptr->elements[x], 0, sizeof(pst_mapi_element)); //init it
01721 
01722             // check here to see if the id of the attribute is a mapped one
01723             mapptr = pf->x_head;
01724             while (mapptr && (mapptr->map < table_rec.type)) mapptr = mapptr->next;
01725             if (mapptr && (mapptr->map == table_rec.type)) {
01726                 if (mapptr->mytype == PST_MAP_ATTRIB) {
01727                     mo_ptr->elements[x]->mapi_id = *((uint32_t*)mapptr->data);
01728                     DEBUG_INFO(("Mapped attrib %#x to %#x\n", table_rec.type, mo_ptr->elements[x]->mapi_id));
01729                 } else if (mapptr->mytype == PST_MAP_HEADER) {
01730                     DEBUG_INFO(("Internet Header mapping found %#"PRIx32" to %s\n", table_rec.type, mapptr->data));
01731                     mo_ptr->elements[x]->mapi_id = (uint32_t)PST_ATTRIB_HEADER;
01732                     mo_ptr->elements[x]->extra   = mapptr->data;
01733                 }
01734                 else {
01735                     DEBUG_WARN(("Missing assertion failure\n"));
01736                     // nothing, should be assertion failure here
01737                 }
01738             } else {
01739                 mo_ptr->elements[x]->mapi_id = table_rec.type;
01740             }
01741             mo_ptr->elements[x]->type = 0; // checked later before it is set
01742             /* Reference Types
01743                 0x0002 - Signed 16bit value
01744                 0x0003 - Signed 32bit value
01745                 0x0004 - 4-byte floating point
01746                 0x0005 - Floating point double
01747                 0x0006 - Signed 64-bit int
01748                 0x0007 - Application Time
01749                 0x000A - 32-bit error value
01750                 0x000B - Boolean (non-zero = true)
01751                 0x000D - Embedded Object
01752                 0x0014 - 8-byte signed integer (64-bit)
01753                 0x001E - Null terminated String
01754                 0x001F - Unicode string
01755                 0x0040 - Systime - Filetime structure
01756                 0x0048 - OLE Guid
01757                 0x0102 - Binary data
01758                 0x1003 - Array of 32bit values
01759                 0x1014 - Array of 64bit values
01760                 0x101E - Array of Strings
01761                 0x1102 - Array of Binary data
01762             */
01763 
01764             if (table_rec.ref_type == (uint16_t)0x0002 ||
01765                 table_rec.ref_type == (uint16_t)0x0003 ||
01766                 table_rec.ref_type == (uint16_t)0x000b) {
01767                 //contains 32 bits of data
01768                 mo_ptr->elements[x]->size = sizeof(int32_t);
01769                 mo_ptr->elements[x]->type = table_rec.ref_type;
01770                 mo_ptr->elements[x]->data = pst_malloc(sizeof(int32_t));
01771                 memcpy(mo_ptr->elements[x]->data, &(table_rec.value), sizeof(int32_t));
01772                 // are we missing an LE32_CPU() call here? table_rec.value is still
01773                 // in the original order.
01774 
01775             } else if (table_rec.ref_type == (uint16_t)0x0005 ||
01776                        table_rec.ref_type == (uint16_t)0x000d ||
01777                        table_rec.ref_type == (uint16_t)0x0014 ||
01778                        table_rec.ref_type == (uint16_t)0x001e ||
01779                        table_rec.ref_type == (uint16_t)0x001f ||
01780                        table_rec.ref_type == (uint16_t)0x0040 ||
01781                        table_rec.ref_type == (uint16_t)0x0048 ||
01782                        table_rec.ref_type == (uint16_t)0x0102 ||
01783                        table_rec.ref_type == (uint16_t)0x1003 ||
01784                        table_rec.ref_type == (uint16_t)0x1014 ||
01785                        table_rec.ref_type == (uint16_t)0x101e ||
01786                        table_rec.ref_type == (uint16_t)0x101f ||
01787                        table_rec.ref_type == (uint16_t)0x1102) {
01788                 //contains index reference to data
01789                 LE32_CPU(table_rec.value);
01790                 if (value_pointer) {
01791                     // in a type 2 block, with a value that is more than 4 bytes
01792                     // directly stored in this block.
01793                     mo_ptr->elements[x]->size = value_size;
01794                     mo_ptr->elements[x]->type = table_rec.ref_type;
01795                     mo_ptr->elements[x]->data = pst_malloc(value_size);
01796                     memcpy(mo_ptr->elements[x]->data, value_pointer, value_size);
01797                 }
01798                 else if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, table_rec.value, &block_offset7)) {
01799                     if ((table_rec.value & 0xf) == (uint32_t)0xf) {
01800                         DEBUG_WARN(("failed to get block offset for table_rec.value of %#x to be read later.\n", table_rec.value));
01801                         mo_ptr->elements[x]->size = 0;
01802                         mo_ptr->elements[x]->data = NULL;
01803                         mo_ptr->elements[x]->type = table_rec.value;
01804                     }
01805                     else {
01806                         if (table_rec.value) {
01807                             DEBUG_WARN(("failed to get block offset for table_rec.value of %#x\n", table_rec.value));
01808                         }
01809                         mo_ptr->count_elements --; //we will be skipping a row
01810                         continue;
01811                     }
01812                 }
01813                 else {
01814                     value_size = (size_t)(block_offset7.to - block_offset7.from);
01815                     mo_ptr->elements[x]->size = value_size;
01816                     mo_ptr->elements[x]->type = table_rec.ref_type;
01817                     mo_ptr->elements[x]->data = pst_malloc(value_size+1);
01818                     memcpy(mo_ptr->elements[x]->data, block_offset7.from, value_size);
01819                     mo_ptr->elements[x]->data[value_size] = '\0';  // it might be a string, null terminate it.
01820                 }
01821                 if (table_rec.ref_type == (uint16_t)0xd) {
01822                     // there is still more to do for the type of 0xD embedded objects
01823                     type_d_rec = (struct _type_d_rec*) mo_ptr->elements[x]->data;
01824                     LE32_CPU(type_d_rec->id);
01825                     mo_ptr->elements[x]->size = pst_ff_getID2block(pf, type_d_rec->id, i2_head, &(mo_ptr->elements[x]->data));
01826                     if (!mo_ptr->elements[x]->size){
01827                         DEBUG_WARN(("not able to read the ID2 data. Setting to be read later. %#x\n", type_d_rec->id));
01828                         mo_ptr->elements[x]->type = type_d_rec->id;    // fetch before freeing data, alias pointer
01829                         free(mo_ptr->elements[x]->data);
01830                         mo_ptr->elements[x]->data = NULL;
01831                     }
01832                 }
01833                 if (table_rec.ref_type == (uint16_t)0x1f) {
01834                     // there is more to do for the type 0x1f unicode strings
01835                     size_t rc;
01836                     static pst_vbuf *utf16buf = NULL;
01837                     static pst_vbuf *utf8buf  = NULL;
01838                     if (!utf16buf) utf16buf = pst_vballoc((size_t)1024);
01839                     if (!utf8buf)  utf8buf  = pst_vballoc((size_t)1024);
01840 
01841                     //need UTF-16 zero-termination
01842                     pst_vbset(utf16buf, mo_ptr->elements[x]->data, mo_ptr->elements[x]->size);
01843                     pst_vbappend(utf16buf, "\0\0", (size_t)2);
01844                     DEBUG_INFO(("Iconv in:\n"));
01845                     DEBUG_HEXDUMPC(utf16buf->b, utf16buf->dlen, 0x10);
01846                     rc = pst_vb_utf16to8(utf8buf, utf16buf->b, utf16buf->dlen);
01847                     if (rc == (size_t)-1) {
01848                         DEBUG_WARN(("Failed to convert utf-16 to utf-8\n"));
01849                     }
01850                     else {
01851                         free(mo_ptr->elements[x]->data);
01852                         mo_ptr->elements[x]->size = utf8buf->dlen;
01853                         mo_ptr->elements[x]->data = pst_malloc(utf8buf->dlen);
01854                         memcpy(mo_ptr->elements[x]->data, utf8buf->b, utf8buf->dlen);
01855                     }
01856                     DEBUG_INFO(("Iconv out:\n"));
01857                     DEBUG_HEXDUMPC(mo_ptr->elements[x]->data, mo_ptr->elements[x]->size, 0x10);
01858                 }
01859                 if (mo_ptr->elements[x]->type == 0) mo_ptr->elements[x]->type = table_rec.ref_type;
01860             } else {
01861                 DEBUG_WARN(("ERROR Unknown ref_type %#hx\n", table_rec.ref_type));
01862                 freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01863                 pst_free_list(mo_head);
01864                 DEBUG_RET();
01865                 return NULL;
01866             }
01867             x++;
01868         }
01869         DEBUG_INFO(("increasing ind2_ptr by %i [%#x] bytes. Was %#x, Now %#x\n", rec_size, rec_size, ind2_ptr, ind2_ptr+rec_size));
01870         ind2_ptr += rec_size;
01871     }
01872     freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
01873     DEBUG_RET();
01874     return mo_head;
01875 }
01876 
01877 
01878 // This version of free does NULL check first
01879 #define SAFE_FREE(x) {if (x) free(x);}
01880 #define SAFE_FREE_STR(x) SAFE_FREE(x.str)
01881 #define SAFE_FREE_BIN(x) SAFE_FREE(x.data)
01882 
01883 // check if item->email is NULL, and init if so
01884 #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)        );} }
01885 #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)       );} }
01886 #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)      );} }
01887 #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));} }
01888 #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)      );} }
01889 #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)  );} }
01890 
01891 // malloc space and copy the current item's data null terminated
01892 #define LIST_COPY(targ, type) {                                    \
01893     targ = type pst_realloc(targ, list->elements[x]->size+1);      \
01894     memcpy(targ, list->elements[x]->data, list->elements[x]->size);\
01895     memset(((char*)targ)+list->elements[x]->size, 0, (size_t)1);   \
01896 }
01897 
01898 #define LIST_COPY_CSTR(targ) {                                              \
01899     if ((list->elements[x]->type == 0x1f) ||                                \
01900         (list->elements[x]->type == 0x1e) ||                                \
01901         (list->elements[x]->type == 0x102)) {                               \
01902         LIST_COPY(targ, (char*))                                            \
01903     }                                                                       \
01904     else {                                                                  \
01905         DEBUG_WARN(("src not 0x1e or 0x1f or 0x102 for string dst\n"));     \
01906         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);    \
01907         SAFE_FREE(targ);                                                    \
01908         targ = NULL;                                                        \
01909     }                                                                       \
01910 }
01911 
01912 #define LIST_COPY_BOOL(label, targ) {                                       \
01913     if (list->elements[x]->type != 0x0b) {                                  \
01914         DEBUG_WARN(("src not 0x0b for boolean dst\n"));                     \
01915         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);    \
01916     }                                                                       \
01917     if (*(int16_t*)list->elements[x]->data) {                               \
01918         DEBUG_INFO((label" - True\n"));                                     \
01919         targ = 1;                                                           \
01920     } else {                                                                \
01921         DEBUG_INFO((label" - False\n"));                                    \
01922         targ = 0;                                                           \
01923     }                                                                       \
01924 }
01925 
01926 #define LIST_COPY_EMAIL_BOOL(label, targ) {                     \
01927     MALLOC_EMAIL(item);                                         \
01928     LIST_COPY_BOOL(label, targ)                                 \
01929 }
01930 
01931 #define LIST_COPY_CONTACT_BOOL(label, targ) {                   \
01932     MALLOC_CONTACT(item);                                       \
01933     LIST_COPY_BOOL(label, targ)                                 \
01934 }
01935 
01936 #define LIST_COPY_APPT_BOOL(label, targ) {                      \
01937     MALLOC_APPOINTMENT(item);                                   \
01938     LIST_COPY_BOOL(label, targ)                                 \
01939 }
01940 
01941 #define LIST_COPY_INT16_N(targ) {                                           \
01942     if (list->elements[x]->type != 0x02) {                                  \
01943         DEBUG_WARN(("src not 0x02 for int16 dst\n"));                       \
01944         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);    \
01945     }                                                                       \
01946     memcpy(&(targ), list->elements[x]->data, sizeof(targ));                 \
01947     LE16_CPU(targ);                                                         \
01948 }
01949 
01950 #define LIST_COPY_INT16(label, targ) {                          \
01951     LIST_COPY_INT16_N(targ);                                    \
01952     DEBUG_INFO((label" - %i %#x\n", (int)targ, (int)targ));     \
01953 }
01954 
01955 #define LIST_COPY_INT32_N(targ) {                                           \
01956     if (list->elements[x]->type != 0x03) {                                  \
01957         DEBUG_WARN(("src not 0x03 for int32 dst\n"));                       \
01958         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);    \
01959     }                                                                       \
01960     memcpy(&(targ), list->elements[x]->data, sizeof(targ));                 \
01961     LE32_CPU(targ);                                                         \
01962 }
01963 
01964 #define LIST_COPY_INT32(label, targ) {                          \
01965     LIST_COPY_INT32_N(targ);                                    \
01966     DEBUG_INFO((label" - %i %#x\n", (int)targ, (int)targ));     \
01967 }
01968 
01969 #define LIST_COPY_EMAIL_INT32(label, targ) {                    \
01970     MALLOC_EMAIL(item);                                         \
01971     LIST_COPY_INT32(label, targ);                               \
01972 }
01973 
01974 #define LIST_COPY_APPT_INT32(label, targ) {                     \
01975     MALLOC_APPOINTMENT(item);                                   \
01976     LIST_COPY_INT32(label, targ);                               \
01977 }
01978 
01979 #define LIST_COPY_FOLDER_INT32(label, targ) {                   \
01980     MALLOC_FOLDER(item);                                        \
01981     LIST_COPY_INT32(label, targ);                               \
01982 }
01983 
01984 #define LIST_COPY_STORE_INT32(label, targ) {                    \
01985     MALLOC_MESSAGESTORE(item);                                  \
01986     LIST_COPY_INT32(label, targ);                               \
01987 }
01988 
01989 #define LIST_COPY_ENUM(label, targ, delta, count, ...) {        \
01990     char *tlabels[] = {__VA_ARGS__};                            \
01991     LIST_COPY_INT32_N(targ);                                    \
01992     targ += delta;                                              \
01993     DEBUG_INFO((label" - %s [%i]\n",                            \
01994         (((int)targ < 0) || ((int)targ >= count))               \
01995             ? "**invalid"                                       \
01996             : tlabels[(int)targ], (int)targ));                  \
01997 }
01998 
01999 #define LIST_COPY_EMAIL_ENUM(label, targ, delta, count, ...) {  \
02000     MALLOC_EMAIL(item);                                         \
02001     LIST_COPY_ENUM(label, targ, delta, count, __VA_ARGS__);     \
02002 }
02003 
02004 #define LIST_COPY_APPT_ENUM(label, targ, delta, count, ...) {   \
02005     MALLOC_APPOINTMENT(item);                                   \
02006     LIST_COPY_ENUM(label, targ, delta, count, __VA_ARGS__);     \
02007 }
02008 
02009 #define LIST_COPY_ENUM16(label, targ, delta, count, ...) {      \
02010     char *tlabels[] = {__VA_ARGS__};                            \
02011     LIST_COPY_INT16_N(targ);                                    \
02012     targ += delta;                                              \
02013     DEBUG_INFO((label" - %s [%i]\n",                            \
02014         (((int)targ < 0) || ((int)targ >= count))               \
02015             ? "**invalid"                                       \
02016             : tlabels[(int)targ], (int)targ));                  \
02017 }
02018 
02019 #define LIST_COPY_CONTACT_ENUM16(label, targ, delta, count, ...) {  \
02020     MALLOC_CONTACT(item);                                           \
02021     LIST_COPY_ENUM16(label, targ, delta, count, __VA_ARGS__);       \
02022 }
02023 
02024 #define LIST_COPY_ENTRYID(label, targ) {                        \
02025     LIST_COPY(targ, (pst_entryid*));                            \
02026     LE32_CPU(targ->u1);                                         \
02027     LE32_CPU(targ->id);                                         \
02028     DEBUG_INFO((label" u1=%#x, id=%#x\n", targ->u1, targ->id)); \
02029 }
02030 
02031 #define LIST_COPY_EMAIL_ENTRYID(label, targ) {                  \
02032     MALLOC_EMAIL(item);                                         \
02033     LIST_COPY_ENTRYID(label, targ);                             \
02034 }
02035 
02036 #define LIST_COPY_STORE_ENTRYID(label, targ) {                  \
02037     MALLOC_MESSAGESTORE(item);                                  \
02038     LIST_COPY_ENTRYID(label, targ);                             \
02039 }
02040 
02041 
02042 // malloc space and copy the current item's data null terminated
02043 // including the utf8 flag
02044 #define LIST_COPY_STR(label, targ) {                                    \
02045     LIST_COPY_CSTR(targ.str);                                           \
02046     targ.is_utf8 = (list->elements[x]->type == 0x1f) ? 1 : 0;           \
02047     DEBUG_INFO((label" - unicode %d - %s\n", targ.is_utf8, targ.str));  \
02048 }
02049 
02050 #define LIST_COPY_EMAIL_STR(label, targ) {                      \
02051     MALLOC_EMAIL(item);                                         \
02052     LIST_COPY_STR(label, targ);                                 \
02053 }
02054 
02055 #define LIST_COPY_CONTACT_STR(label, targ) {                    \
02056     MALLOC_CONTACT(item);                                       \
02057     LIST_COPY_STR(label, targ);                                 \
02058 }
02059 
02060 #define LIST_COPY_APPT_STR(label, targ) {                       \
02061     MALLOC_APPOINTMENT(item);                                   \
02062     LIST_COPY_STR(label, targ);                                 \
02063 }
02064 
02065 #define LIST_COPY_JOURNAL_STR(label, targ) {                    \
02066     MALLOC_JOURNAL(item);                                       \
02067     LIST_COPY_STR(label, targ);                                 \
02068 }
02069 
02070 // malloc space and copy the item filetime
02071 #define LIST_COPY_TIME(label, targ) {                                       \
02072     if ((list->elements[x]->type != 0x40) ||                                \
02073         (list->elements[x]->size != sizeof(FILETIME))) {                    \
02074         DEBUG_WARN(("src not 0x40 or wrong length for filetime dst\n"));    \
02075         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);    \
02076     }                                                                       \
02077     else {                                                                  \
02078         targ = (FILETIME*) pst_realloc(targ, sizeof(FILETIME));             \
02079         memcpy(targ, list->elements[x]->data, sizeof(FILETIME));            \
02080         LE32_CPU(targ->dwLowDateTime);                                      \
02081         LE32_CPU(targ->dwHighDateTime);                                     \
02082         DEBUG_INFO((label" - %s", pst_fileTimeToAscii(targ, time_buffer))); \
02083     }                                                                       \
02084 }
02085 
02086 #define LIST_COPY_EMAIL_TIME(label, targ) {                     \
02087     MALLOC_EMAIL(item);                                         \
02088     LIST_COPY_TIME(label, targ);                                \
02089 }
02090 
02091 #define LIST_COPY_CONTACT_TIME(label, targ) {                   \
02092     MALLOC_CONTACT(item);                                       \
02093     LIST_COPY_TIME(label, targ);                                \
02094 }
02095 
02096 #define LIST_COPY_APPT_TIME(label, targ) {                      \
02097     MALLOC_APPOINTMENT(item);                                   \
02098     LIST_COPY_TIME(label, targ);                                \
02099 }
02100 
02101 #define LIST_COPY_JOURNAL_TIME(label, targ) {                   \
02102     MALLOC_JOURNAL(item);                                       \
02103     LIST_COPY_TIME(label, targ);                                \
02104 }
02105 
02106 // malloc space and copy the current item's data and size
02107 #define LIST_COPY_BIN(targ) {                                       \
02108     targ.size = list->elements[x]->size;                            \
02109     if (targ.size) {                                                \
02110         targ.data = (char*)pst_realloc(targ.data, targ.size);       \
02111         memcpy(targ.data, list->elements[x]->data, targ.size);      \
02112     }                                                               \
02113     else {                                                          \
02114         SAFE_FREE_BIN(targ);                                        \
02115         targ.data = NULL;                                           \
02116     }                                                               \
02117 }
02118 
02119 #define LIST_COPY_EMAIL_BIN(label, targ) {          \
02120     MALLOC_EMAIL(item);                             \
02121     LIST_COPY_BIN(targ);                            \
02122     DEBUG_INFO((label"\n"));                        \
02123 }
02124 #define LIST_COPY_APPT_BIN(label, targ) {           \
02125     MALLOC_APPOINTMENT(item);                       \
02126     LIST_COPY_BIN(targ);                            \
02127     DEBUG_INFO((label"\n"));                        \
02128     DEBUG_HEXDUMP(targ.data, targ.size);            \
02129 }
02130 
02131 #define NULL_CHECK(x) { if (!x) { DEBUG_WARN(("NULL_CHECK: Null Found\n")); break;} }
02132 
02133 
02149 static int pst_process(uint64_t block_id, pst_mapi_object *list, pst_item *item, pst_item_attach *attach) {
02150     DEBUG_ENT("pst_process");
02151     if (!item) {
02152         DEBUG_WARN(("item cannot be NULL.\n"));
02153         DEBUG_RET();
02154         return -1;
02155     }
02156 
02157     item->block_id = block_id;
02158     while (list) {
02159         int32_t x;
02160         char time_buffer[30];
02161         for (x=0; x<list->count_elements; x++) {
02162             int32_t t;
02163             uint32_t ut;
02164             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));
02165 
02166             switch (list->elements[x]->mapi_id) {
02167                 case PST_ATTRIB_HEADER: // CUSTOM attribute for saying the Extra Headers
02168                     if (list->elements[x]->extra) {
02169                         if (list->elements[x]->type == 0x0101e) {
02170                             // an array of strings, rather than a single string
02171                             int32_t string_length, i, offset, next_offset;
02172                             int32_t p = 0;
02173                             int32_t array_element_count = PST_LE_GET_INT32(list->elements[x]->data); p+=4;
02174                             for (i = 1; i <= array_element_count; i++) {
02175                                 pst_item_extra_field *ef = (pst_item_extra_field*) pst_malloc(sizeof(pst_item_extra_field));
02176                                 memset(ef, 0, sizeof(pst_item_extra_field));
02177                                 offset      = PST_LE_GET_INT32(list->elements[x]->data + p); p+=4;
02178                                 next_offset = (i == array_element_count) ? list->elements[x]->size : PST_LE_GET_INT32(list->elements[x]->data + p);;
02179                                 string_length = next_offset - offset;
02180                                 ef->value = pst_malloc(string_length + 1);
02181                                 memcpy(ef->value, list->elements[x]->data + offset, string_length);
02182                                 ef->value[string_length] = '\0';
02183                                 ef->field_name = strdup(list->elements[x]->extra);
02184                                 ef->next       = item->extra_fields;
02185                                 item->extra_fields = ef;
02186                                 DEBUG_INFO(("Extra Field - \"%s\" = \"%s\"\n", ef->field_name, ef->value));
02187                             }
02188                         }
02189                         else {
02190                             // should be a single string
02191                             pst_item_extra_field *ef = (pst_item_extra_field*) pst_malloc(sizeof(pst_item_extra_field));
02192                             memset(ef, 0, sizeof(pst_item_extra_field));
02193                             LIST_COPY_CSTR(ef->value);
02194                             if (ef->value) {
02195                                 ef->field_name = strdup(list->elements[x]->extra);
02196                                 ef->next       = item->extra_fields;
02197                                 item->extra_fields = ef;
02198                                 DEBUG_INFO(("Extra Field - \"%s\" = \"%s\"\n", ef->field_name, ef->value));
02199                                 if (strcmp(ef->field_name, "content-type") == 0) {
02200                                     char *p = strstr(ef->value, "charset=\"");
02201                                     if (p) {
02202                                         p += 9; // skip over charset="
02203                                         char *pp = strchr(p, '"');
02204                                         if (pp) {
02205                                             *pp = '\0';
02206                                             char *set = strdup(p);
02207                                             *pp = '"';
02208                                             if (item->body_charset.str) free(item->body_charset.str);
02209                                             item->body_charset.str     = set;
02210                                             item->body_charset.is_utf8 = 1;
02211                                             DEBUG_INFO(("body charset %s from content-type extra field\n", set));
02212                                         }
02213                                     }
02214                                 }
02215                             }
02216                             else {
02217                                 DEBUG_WARN(("What does this mean? Internet header %s value\n", list->elements[x]->extra));
02218                                 DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02219                                 free(ef);   // caught by valgrind
02220                             }
02221                         }
02222                     }
02223                     break;
02224                 case 0x0002: // PR_ALTERNATE_RECIPIENT_ALLOWED
02225                     if (list->elements[x]->type == 0x0b) {
02226                         // If set to true, the sender allows this email to be autoforwarded
02227                         LIST_COPY_EMAIL_BOOL("AutoForward allowed", item->email->autoforward);
02228                         if (!item->email->autoforward) item->email->autoforward = -1;
02229                     } else {
02230                         DEBUG_WARN(("What does this mean?\n"));
02231                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02232                     }
02233                     break;
02234                 case 0x0003: // Extended Attributes table
02235                     DEBUG_INFO(("Extended Attributes Table - NOT PROCESSED\n"));
02236                     break;
02237                 case 0x0017: // PR_IMPORTANCE - How important the sender deems it to be
02238                     LIST_COPY_EMAIL_ENUM("Importance Level", item->email->importance, 0, 3, "Low", "Normal", "High");
02239                     break;
02240                 case 0x001A: // PR_MESSAGE_CLASS IPM.x
02241                     if ((list->elements[x]->type == 0x1e) ||
02242                         (list->elements[x]->type == 0x1f)) {
02243                         LIST_COPY_CSTR(item->ascii_type);
02244                         if (!item->ascii_type) item->ascii_type = strdup("unknown");
02245                         if (pst_strincmp("IPM.Note", item->ascii_type, 8) == 0)
02246                             item->type = PST_TYPE_NOTE;
02247                         else if (pst_stricmp("IPM", item->ascii_type) == 0)
02248                             item->type = PST_TYPE_NOTE;
02249                         else if (pst_strincmp("IPM.Contact", item->ascii_type, 11) == 0)
02250                             item->type = PST_TYPE_CONTACT;
02251                         else if (pst_strincmp("REPORT.IPM.Note", item->ascii_type, 15) == 0)
02252                             item->type = PST_TYPE_REPORT;
02253                         else if (pst_strincmp("IPM.Activity", item->ascii_type, 12) == 0)
02254                             item->type = PST_TYPE_JOURNAL;
02255                         else if (pst_strincmp("IPM.Appointment", item->ascii_type, 15) == 0)
02256                             item->type = PST_TYPE_APPOINTMENT;
02257                         else if (pst_strincmp("IPM.Schedule.Meeting", item->ascii_type, 20) == 0)
02258                             item->type = PST_TYPE_SCHEDULE;     // meeting requests and responses transported over email
02259                         else if (pst_strincmp("IPM.StickyNote", item->ascii_type, 14) == 0)
02260                             item->type = PST_TYPE_STICKYNOTE;
02261                         else if (pst_strincmp("IPM.Task", item->ascii_type, 8) == 0)
02262                             item->type = PST_TYPE_TASK;
02263                         else
02264                             item->type = PST_TYPE_OTHER;
02265                         DEBUG_INFO(("Message class %s [%"PRIi32"] \n", item->ascii_type, item->type));
02266                     }
02267                     else {
02268                         DEBUG_WARN(("What does this mean?\n"));
02269                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02270                     }
02271                     break;
02272                 case 0x0023: // PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED
02273                     if (list->elements[x]->type == 0x0b) {
02274                         // set if the sender wants a delivery report from all recipients
02275                         LIST_COPY_EMAIL_BOOL("Global Delivery Report", item->email->delivery_report);
02276                     }
02277                     else {
02278                         DEBUG_WARN(("What does this mean?\n"));
02279                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
02280                     }
02281                     break;
02282                 case 0x0026: // PR_PRIORITY
02283                     LIST_COPY_EMAIL_ENUM("Priority", item->email->priority, 1, 3, "NonUrgent", "Normal", "Urgent");
02284                     break;
02285                 case 0x0029: // PR_READ_RECEIPT_REQUESTED
02286                     LIST_COPY_EMAIL_BOOL("Read Receipt", item->email->read_receipt);
02287                     break;
02288                 case 0x002B: // PR_RECIPIENT_REASSIGNMENT_PROHIBITED
02289                     LIST_COPY_BOOL("Reassignment Prohibited (Private)", item->private_member);
02290                     break;
02291                 case 0x002E: // PR_ORIGINAL_SENSITIVITY - the sensitivity of the message before being replied to or forwarded
02292                     LIST_COPY_EMAIL_ENUM("Original Sensitivity", item->email->original_sensitivity, 0, 4,
02293                         "None", "Personal", "Private", "Company Confidential");
02294                     break;
02295                 case 0x0032: // PR_REPORT_TIME
02296                     LIST_COPY_EMAIL_TIME("Report time", item->email->report_time);
02297                     break;
02298                 case 0x0036: // PR_SENSITIVITY - sender's opinion of the sensitivity of an email
02299                     LIST_COPY_EMAIL_ENUM("Sensitivity", item->email->sensitivity, 0, 4,
02300                         "None", "Personal", "Private", "Company Confidential");
02301                     break;
02302                 case 0x0037: // PR_SUBJECT raw subject
02303                     {
02304                         int off = 0;
02305                         if ((list->elements[x]->size > 2) && (((uint8_t)list->elements[x]->data[0]) < 0x20)) {
02306                             off = 2;
02307                         }
02308                         list->elements[x]->data += off;
02309                         list->elements[x]->size -= off;
02310                         LIST_COPY_STR("Raw Subject", item->subject);
02311                         list->elements[x]->size += off;
02312                         list->elements[x]->data -= off;
02313                     }
02314                     break;
02315                 case 0x0039: // PR_CLIENT_SUBMIT_TIME Date Email Sent/Created
02316                     LIST_COPY_EMAIL_TIME("Date sent", item->email->sent_date);
02317                     break;
02318                 case 0x003B: // PR_SENT_REPRESENTING_SEARCH_KEY Sender address 1
02319                     LIST_COPY_EMAIL_STR("Sent on behalf of address 1", item->email->outlook_sender);
02320                     break;
02321                 case 0x003F: // PR_RECEIVED_BY_ENTRYID Structure containing Recipient
02322                     DEBUG_INFO(("Recipient Structure 1 -- NOT PROCESSED\n"));
02323                     break;
02324                 case 0x0040: // PR_RECEIVED_BY_NAME Name of Recipient Structure
02325                     LIST_COPY_EMAIL_STR("Received By Name 1", item->email->outlook_received_name1);
02326                     break;
02327                 case 0x0041: // PR_SENT_REPRESENTING_ENTRYID Structure containing Sender
02328                     DEBUG_INFO(("Sent on behalf of Structure 1 -- NOT PROCESSED\n"));
02329                     break;
02330                 case 0x0042: // PR_SENT_REPRESENTING_NAME
02331                     LIST_COPY_EMAIL_STR("Sent on behalf of", item->email->outlook_sender_name);
02332                     break;
02333                 case 0x0043: // PR_RCVD_REPRESENTING_ENTRYID Recipient Structure 2
02334                     DEBUG_INFO(("Received on behalf of Structure -- NOT PROCESSED\n"));
02335                     break;
02336                 case 0x0044: // PR_RCVD_REPRESENTING_NAME
02337                     LIST_COPY_EMAIL_STR("Received on behalf of", item->email->outlook_recipient_name);
02338                     break;
02339                 case 0x004F: // PR_REPLY_RECIPIENT_ENTRIES Reply-To Structure
02340                     DEBUG_INFO(("Reply-To Structure -- NOT PROCESSED\n"));
02341                     break;
02342                 case 0x0050: // PR_REPLY_RECIPIENT_NAMES Name of Reply-To Structure
02343                     LIST_COPY_EMAIL_STR("Reply-To", item->email->reply_to);
02344                     break;
02345                 case 0x0051: // PR_RECEIVED_BY_SEARCH_KEY Recipient Address 1
02346                     LIST_COPY_EMAIL_STR("Recipient's Address 1", item->email->outlook_recipient);
02347                     break;
02348                 case 0x0052: // PR_RCVD_REPRESENTING_SEARCH_KEY Recipient Address 2
02349                     LIST_COPY_EMAIL_STR("Recipient's Address 2", item->email->outlook_recipient2);
02350                     break;
02351                 case 0x0057: // PR_MESSAGE_TO_ME
02352                     // this user is listed explicitly in the TO address
02353                     LIST_COPY_EMAIL_BOOL("My address in TO field", item->email->message_to_me);
02354                     break;
02355                 case 0x0058: // PR_MESSAGE_CC_ME
02356                     // this user is listed explicitly in the CC address
02357                     LIST_COPY_EMAIL_BOOL("My address in CC field", item->email->message_cc_me);
02358                     break;
02359                 case 0x0059: // PR_MESSAGE_RECIP_ME
02360                     // this user appears in TO, CC or BCC address list
02361                     LIST_COPY_EMAIL_BOOL("Message addressed to me", item->email->message_recip_me);
02362                     break;
02363                 case 0x0063: // PR_RESPONSE_REQUESTED
02364                     LIST_COPY_BOOL("Response requested", item->response_requested);
02365                     break;
02366                 case 0x0064: // PR_SENT_REPRESENTING_ADDRTYPE Access method for Sender Address
02367                     LIST_COPY_EMAIL_STR("Sent on behalf of address type", item->email->sender_access);
02368                     break;
02369                 case 0x0065: // PR_SENT_REPRESENTING_EMAIL_ADDRESS Sender Address
02370                     LIST_COPY_EMAIL_STR("Sent on behalf of address", item->email->sender_address);
02371                     break;
02372                 case 0x0070: // PR_CONVERSATION_TOPIC Processed Subject
02373                     LIST_COPY_EMAIL_STR("Processed Subject (Conversation Topic)", item->email->processed_subject);
02374                     break;
02375                 case 0x0071: // PR_CONVERSATION_INDEX
02376                     LIST_COPY_EMAIL_BIN("Conversation Index", item->email->conversation_index);
02377                     break;
02378                 case 0x0072: // PR_ORIGINAL_DISPLAY_BCC
02379                     LIST_COPY_EMAIL_STR("Original display bcc", item->email->original_bcc);
02380                     break;
02381                 case 0x0073: // PR_ORIGINAL_DISPLAY_CC
02382                     LIST_COPY_EMAIL_STR("Original display cc", item->email->original_cc);
02383                     break;
02384                 case 0x0074: // PR_ORIGINAL_DISPLAY_TO
02385                     LIST_COPY_EMAIL_STR("Original display to", item->email->original_to);
02386                     break;
02387                 case 0x0075: // PR_RECEIVED_BY_ADDRTYPE Recipient Access Method
02388                     LIST_COPY_EMAIL_STR("Received by Address type", item->email->recip_access);
02389                     break;
02390                 case 0x0076: // PR_RECEIVED_BY_EMAIL_ADDRESS Recipient Address
02391                     LIST_COPY_EMAIL_STR("Received by Address", item->email->recip_address);
02392                     break;
02393                 case 0x0077: // PR_RCVD_REPRESENTING_ADDRTYPE Recipient Access Method 2
02394                     LIST_COPY_EMAIL_STR("Received on behalf of Address type", item->email->recip2_access);
02395                     break;
02396                 case 0x0078: // PR_RCVD_REPRESENTING_EMAIL_ADDRESS Recipient Address 2
02397                     LIST_COPY_EMAIL_STR("Received on behalf of Address", item->email->recip2_address);
02398                     break;
02399                 case 0x007D: // PR_TRANSPORT_MESSAGE_HEADERS Internet Header
02400                     LIST_COPY_EMAIL_STR("Internet Header", item->email->header);
02401                     break;
02402                 case 0x0C04: // PR_NDR_REASON_CODE
02403                     LIST_COPY_EMAIL_INT32("NDR reason code", item->email->ndr_reason_code);
02404                     break;
02405                 case 0x0C05: // PR_NDR_DIAG_CODE
02406                     LIST_COPY_EMAIL_INT32("NDR diag code", item->email->ndr_diag_code);
02407                     break;
02408                 case 0x0C06: // PR_NON_RECEIPT_NOTIFICATION_REQUESTED
02409                     DEBUG_INFO(("Non-Receipt Notification Requested -- NOT PROCESSED\n"));
02410                     break;
02411                 case 0x0C17: // PR_REPLY_REQUESTED
02412                     LIST_COPY_EMAIL_BOOL("Reply Requested", item->email->reply_requested);
02413                     break;
02414                 case 0x0C19: // PR_SENDER_ENTRYID Sender Structure 2
02415                     DEBUG_INFO(("Sender Structure 2 -- NOT PROCESSED\n"));
02416                     break;
02417                 case 0x0C1A: // PR_SENDER_NAME Name of Sender Structure 2
02418                     LIST_COPY_EMAIL_STR("Name of Sender Structure 2", item->email->outlook_sender_name2);
02419                     break;
02420                 case 0x0C1B: // PR_SUPPLEMENTARY_INFO
02421                     LIST_COPY_EMAIL_STR("Supplementary info", item->email->supplementary_info);
02422                     break;
02423                 case 0x0C1D: // PR_SENDER_SEARCH_KEY Name of Sender Address 2
02424                     LIST_COPY_EMAIL_STR("Name of Sender Address 2 (Sender search key)", item->email->outlook_sender2);
02425                     break;
02426                 case 0x0C1E: // PR_SENDER_ADDRTYPE Sender Address 2 access method
02427                     LIST_COPY_EMAIL_STR("Sender Address type", item->email->sender2_access);
02428                     break;
02429                 case 0x0C1F: // PR_SENDER_EMAIL_ADDRESS Sender Address 2
02430                     LIST_COPY_EMAIL_STR("Sender Address", item->email->sender2_address);
02431                     break;
02432                 case 0x0C20: // PR_NDR_STATUS_CODE
02433                     LIST_COPY_EMAIL_INT32("NDR status code", item->email->ndr_status_code);
02434                     break;
02435                 case 0x0E01: // PR_DELETE_AFTER_SUBMIT
02436                     LIST_COPY_EMAIL_BOOL("Delete after submit", item->email->delete_after_submit);
02437                     break;
02438                 case 0x0E02: // PR_DISPLAY_BCC BCC Addresses
02439                     LIST_COPY_EMAIL_STR("Display BCC Addresses", item->email->bcc_address);
02440                     break;
02441                 case 0x0E03: // PR_DISPLAY_CC CC Addresses
02442                     LIST_COPY_EMAIL_STR("Display CC Addresses", item->email->cc_address);
02443                     break;
02444                 case 0x0E04: // PR_DISPLAY_TO Address Sent-To
02445                     LIST_COPY_EMAIL_STR("Display Sent-To Address", item->email->sentto_address);
02446                     break;
02447                 case 0x0E06: // PR_MESSAGE_DELIVERY_TIME Date 3 - Email Arrival Date
02448                     LIST_COPY_EMAIL_TIME("Date 3 (Delivery Time)", item->email->arrival_date);
02449                     break;
02450                 case 0x0E07: // PR_MESSAGE_FLAGS Email Flag
02451                     LIST_COPY_EMAIL_INT32("Message Flags", item->flags);
02452                     break;
02453                 case 0x0E08: // PR_MESSAGE_SIZE Total size of a message object
02454                     LIST_COPY_INT32("Message Size", item->message_size);
02455                     break;
02456                 case 0x0E0A: // PR_SENTMAIL_ENTRYID
02457                     // folder that this message is sent to after submission
02458                     LIST_COPY_EMAIL_ENTRYID("Sentmail EntryID", item->email->sentmail_folder);
02459                     break;
02460                 case 0x0E1D: // PR_NORMALIZED_SUBJECT
02461                     LIST_COPY_EMAIL_STR("Normalized subject", item->email->outlook_normalized_subject);
02462                     break;
02463                 case 0x0E1F: // PR_RTF_IN_SYNC
02464                     // True means that the rtf version is same as text body
02465                     // False means rtf version is more up-to-date than text body
02466                     // if this value doesn't exist, text body is more up-to-date than rtf and
02467                     // cannot update to the rtf
02468                     LIST_COPY_EMAIL_BOOL("Compressed RTF in Sync", item->email->rtf_in_sync);
02469                     break;
02470                 case 0x0E20: // PR_ATTACH_SIZE binary Attachment data in record
02471                     NULL_CHECK(attach);
02472                     LIST_COPY_INT32("Attachment Size", t);
02473                     // ignore this. we either get data and size from 0x3701
02474                     // or id codes from 0x3701 or 0x67f2
02475                     break;
02476                 case 0x0FF9: // PR_RECORD_KEY Record Header 1
02477                     LIST_COPY_BIN(item->record_key);
02478                     DEBUG_INFO(("Record Key\n"));
02479                     DEBUG_HEXDUMP(item->record_key.data, item->record_key.size);
02480                     break;
02481                 case 0x1000: // PR_BODY
02482                     LIST_COPY_STR("Plain Text body", item->body);
02483                     break;
02484                 case 0x1001: // PR_REPORT_TEXT
02485                     LIST_COPY_EMAIL_STR("Report Text", item->email->report_text);
02486                     break;
02487                 case 0x1006: // PR_RTF_SYNC_BODY_CRC
02488                     LIST_COPY_EMAIL_INT32("RTF Sync Body CRC", item->email->rtf_body_crc);
02489                     break;
02490                 case 0x1007: // PR_RTF_SYNC_BODY_COUNT
02491                     // a count of the *significant* charcters in the rtf body. Doesn't count
02492                     // whitespace and other ignorable characters
02493                     LIST_COPY_EMAIL_INT32("RTF Sync Body character count", item->email->rtf_body_char_count);
02494                     break;
02495                 case 0x1008: // PR_RTF_SYNC_BODY_TAG
02496                     // the first couple of lines of RTF body so that after modification, then beginning can
02497                     // once again be found
02498                     LIST_COPY_EMAIL_STR("RTF Sync body tag", item->email->rtf_body_tag);
02499                     break;
02500                 case 0x1009: // PR_RTF_COMPRESSED - rtf data is lzw compressed
02501                     LIST_COPY_EMAIL_BIN("RTF Compressed body", item->email->rtf_compressed);
02502                     break;
02503                 case 0x1010: // PR_RTF_SYNC_PREFIX_COUNT
02504                     // a count of the ignored characters before the first significant character
02505                     LIST_COPY_EMAIL_INT32("RTF whitespace prefix count", item->email->rtf_ws_prefix_count);
02506                     break;
02507                 case 0x1011: // PR_RTF_SYNC_TRAILING_COUNT
02508                     // a count of the ignored characters after the last significant character
02509                     LIST_COPY_EMAIL_INT32("RTF whitespace tailing count", item->email->rtf_ws_trailing_count);
02510                     break;
02511                 case 0x1013: // HTML body
02512                     LIST_COPY_EMAIL_STR("HTML body", item->email->htmlbody);
02513                     break;
02514                 case 0x1035: // Message ID
02515                     LIST_COPY_EMAIL_STR("Message ID", item->email->messageid);
02516                     break;
02517                 case 0x1042: // in-reply-to
02518                     LIST_COPY_EMAIL_STR("In-Reply-To", item->email->in_reply_to);
02519                     break;
02520                 case 0x1046: // Return Path - this seems to be the message-id of the rfc822 mail that is being returned
02521                     LIST_COPY_EMAIL_STR("Return Path", item->email->return_path_address);
02522                     break;
02523                 case 0x3001: // PR_DISPLAY_NAME File As
02524                     LIST_COPY_STR("Display Name", item->file_as);
02525                     break;
02526                 case 0x3002: // PR_ADDRTYPE
02527                     LIST_COPY_CONTACT_STR("Address Type", item->contact->address1_transport);
02528                     break;
02529                 case 0x3003: // PR_EMAIL_ADDRESS
02530                     LIST_COPY_CONTACT_STR("Contact email Address", item->contact->address1);
02531                     break;
02532                 case 0x3004: // PR_COMMENT Comment for item - usually folders
02533                     LIST_COPY_STR("Comment", item->comment);
02534                     break;
02535                 case 0x3007: // PR_CREATION_TIME Date 4 - Creation Date?
02536                     LIST_COPY_TIME("Date 4 (Item Creation Date)", item->create_date);
02537                     break;
02538                 case 0x3008: // PR_LAST_MODIFICATION_TIME Date 5 - Modify Date
02539                     LIST_COPY_TIME("Date 5 (Modify Date)", item->modify_date);
02540                     break;
02541                 case 0x300B: // PR_SEARCH_KEY Record Header 2
02542                     LIST_COPY_EMAIL_STR("Record Search 2", item->email->outlook_search_key);
02543                     break;
02544                 case 0x35DF: // PR_VALID_FOLDER_MASK
02545                     LIST_COPY_STORE_INT32("Valid Folder Mask", item->message_store->valid_mask);
02546                     break;
02547                 case 0x35E0: // PR_IPM_SUBTREE_ENTRYID Top of Personal Folder Record
02548                     LIST_COPY_STORE_ENTRYID("Top of Personal Folder Record", item->message_store->top_of_personal_folder);
02549                     break;
02550                 case 0x35E2: // PR_IPM_OUTBOX_ENTRYID
02551                     LIST_COPY_STORE_ENTRYID("Default Outbox Folder record", item->message_store->default_outbox_folder);
02552                     break;
02553                 case 0x35E3: // PR_IPM_WASTEBASKET_ENTRYID
02554                     LIST_COPY_STORE_ENTRYID("Deleted Items Folder record", item->message_store->deleted_items_folder);
02555                     break;
02556                 case 0x35E4: // PR_IPM_SENTMAIL_ENTRYID
02557                     LIST_COPY_STORE_ENTRYID("Sent Items Folder record", item->message_store->sent_items_folder);
02558                     break;
02559                 case 0x35E5: // PR_VIEWS_ENTRYID
02560                     LIST_COPY_STORE_ENTRYID("User Views Folder record", item->message_store->user_views_folder);
02561                     break;
02562                 case 0x35E6: // PR_COMMON_VIEWS_ENTRYID
02563                     LIST_COPY_STORE_ENTRYID("Common View Folder record", item->message_store->common_view_folder);
02564                     break;
02565                 case 0x35E7: // PR_FINDER_ENTRYID
02566                     LIST_COPY_STORE_ENTRYID("Search Root Folder record", item->message_store->search_root_folder);
02567                     break;
02568                 case 0x3602: // PR_CONTENT_COUNT Number of emails stored in a folder
02569                     LIST_COPY_FOLDER_INT32("Folder Email Count", item->folder->item_count);
02570                     break;
02571                 case 0x3603: // PR_CONTENT_UNREAD Number of unread emails
02572                     LIST_COPY_FOLDER_INT32("Unread Email Count", item->folder->unseen_item_count);
02573                     break;
02574                 case 0x360A: // PR_SUBFOLDERS Has children
02575                     MALLOC_FOLDER(item);
02576                     LIST_COPY_BOOL("Has Subfolders", item->folder->subfolder);
02577                     break;
02578                 case 0x3613: // PR_CONTAINER_CLASS IPF.x
02579                     LIST_COPY_CSTR(item->ascii_type);
02580                     if (pst_strincmp("IPF.Note", item->ascii_type, 8) == 0)
02581                         item->type = PST_TYPE_NOTE;
02582                     else if (pst_strincmp("IPF.Imap", item->ascii_type, 8) == 0)
02583                         item->type = PST_TYPE_NOTE;
02584                     else if (pst_stricmp("IPF", item->ascii_type) == 0)
02585                         item->type = PST_TYPE_NOTE;
02586                     else if (pst_strincmp("IPF.Contact", item->ascii_type, 11) == 0)
02587                         item->type = PST_TYPE_CONTACT;
02588                     else if (pst_strincmp("IPF.Journal", item->ascii_type, 11) == 0)
02589                         item->type = PST_TYPE_JOURNAL;
02590                     else if (pst_strincmp("IPF.Appointment", item->ascii_type, 15) == 0)
02591                         item->type = PST_TYPE_APPOINTMENT;
02592                     else if (pst_strincmp("IPF.StickyNote", item->ascii_type, 14) == 0)
02593                         item->type = PST_TYPE_STICKYNOTE;
02594                     else if (pst_strincmp("IPF.Task", item->ascii_type, 8) == 0)
02595                         item->type = PST_TYPE_TASK;
02596                     else
02597                         item->type = PST_TYPE_OTHER;
02598 
02599                     DEBUG_INFO(("Container class %s [%"PRIi32"]\n", item->ascii_type, item->type));
02600                     break;
02601                 case 0x3617: // PR_ASSOC_CONTENT_COUNT
02602                     // associated content are items that are attached to this folder
02603                     // but are hidden from users
02604                     LIST_COPY_FOLDER_INT32("Associated Content count", item->folder->assoc_count);
02605                     break;
02606                 case 0x3701: // PR_ATTACH_DATA_OBJ binary data of attachment
02607                     DEBUG_INFO(("Binary Data [Size %i]\n", list->elements[x]->size));
02608                     NULL_CHECK(attach);
02609                     if (!list->elements[x]->data) { //special case
02610                         attach->id2_val = list->elements[x]->type;
02611                         DEBUG_INFO(("Seen a Reference. The data hasn't been loaded yet. [%#"PRIx64"]\n", attach->id2_val));
02612                     } else {
02613                         LIST_COPY_BIN(attach->data);
02614                     }
02615                     break;
02616                 case 0x3704: // PR_ATTACH_FILENAME Attachment filename (8.3)
02617                     NULL_CHECK(attach);
02618                     LIST_COPY_STR("Attachment Filename", attach->filename1);
02619                     break;
02620                 case 0x3705: // PR_ATTACH_METHOD
02621                     NULL_CHECK(attach);
02622                     LIST_COPY_ENUM("Attachment method", attach->method, 0, 7,
02623                         "No Attachment",
02624                         "Attach By Value",
02625                         "Attach By Reference",
02626                         "Attach by Reference Resolve",
02627                         "Attach by Reference Only",
02628                         "Embedded Message",
02629                         "OLE");
02630                     break;
02631                 case 0x3707: // PR_ATTACH_LONG_FILENAME Attachment filename (long?)
02632                     NULL_CHECK(attach);
02633                     LIST_COPY_STR("Attachment Filename long", attach->filename2);
02634                     break;
02635                 case 0x370B: // PR_RENDERING_POSITION
02636                     // position in characters that the attachment appears in the plain text body
02637                     NULL_CHECK(attach);
02638                     LIST_COPY_INT32("Attachment Position", attach->position);
02639                     break;
02640                 case 0x370E: // PR_ATTACH_MIME_TAG Mime type of encoding
02641                     NULL_CHECK(attach);
02642                     LIST_COPY_STR("Attachment mime encoding", attach->mimetype);
02643                     break;
02644                 case 0x3710: // PR_ATTACH_MIME_SEQUENCE
02645                     // sequence number for mime parts. Includes body
02646                     NULL_CHECK(attach);
02647                     LIST_COPY_INT32("Attachment Mime Sequence", attach->sequence);
02648                     break;
02649                 case 0x3712: // PR_ATTACH_CONTENT_ID
02650                     // content identification header (Content-ID)
02651                     NULL_CHECK(attach);
02652                     LIST_COPY_STR("Content ID", attach->content_id);
02653                     break;
02654                 case 0x3A00: // PR_ACCOUNT
02655                     LIST_COPY_CONTACT_STR("Contact's Account name", item->contact->account_name);
02656                     break;
02657                 case 0x3A01: // PR_ALTERNATE_RECIPIENT
02658                     DEBUG_INFO(("Contact Alternate Recipient - NOT PROCESSED\n"));
02659                     break;
02660                 case 0x3A02: // PR_CALLBACK_TELEPHONE_NUMBER
02661                     LIST_COPY_CONTACT_STR("Callback telephone number", item->contact->callback_phone);
02662                     break;
02663                 case 0x3A03: // PR_CONVERSION_PROHIBITED
02664                     LIST_COPY_EMAIL_BOOL("Message Conversion Prohibited", item->email->conversion_prohibited);
02665                     break;
02666                 case 0x3A05: // PR_GENERATION suffix
02667                     LIST_COPY_CONTACT_STR("Contacts Suffix", item->contact->suffix);
02668                     break;
02669                 case 0x3A06: // PR_GIVEN_NAME Contact's first name
02670                     LIST_COPY_CONTACT_STR("Contacts First Name", item->contact->first_name);
02671                     break;
02672                 case 0x3A07: // PR_GOVERNMENT_ID_NUMBER
02673                     LIST_COPY_CONTACT_STR("Contacts Government ID Number", item->contact->gov_id);
02674                     break;
02675                 case 0x3A08: // PR_BUSINESS_TELEPHONE_NUMBER
02676                     LIST_COPY_CONTACT_STR("Business Telephone Number", item->contact->business_phone);
02677                     break;
02678                 case 0x3A09: // PR_HOME_TELEPHONE_NUMBER
02679                     LIST_COPY_CONTACT_STR("Home Telephone Number", item->contact->home_phone);
02680                     break;
02681                 case 0x3A0A: // PR_INITIALS Contact's Initials
02682                     LIST_COPY_CONTACT_STR("Contacts Initials", item->contact->initials);
02683                     break;
02684                 case 0x3A0B: // PR_KEYWORD
02685                     LIST_COPY_CONTACT_STR("Keyword", item->contact->keyword);
02686                     break;
02687                 case 0x3A0C: // PR_LANGUAGE
02688                     LIST_COPY_CONTACT_STR("Contact's Language", item->contact->language);
02689                     break;
02690                 case 0x3A0D: // PR_LOCATION
02691                     LIST_COPY_CONTACT_STR("Contact's Location", item->contact->location);
02692                     break;
02693                 case 0x3A0E: // PR_MAIL_PERMISSION - Can the recipient receive and send email
02694                     LIST_COPY_CONTACT_BOOL("Mail Permission", item->contact->mail_permission);
02695                     break;
02696                 case 0x3A0F: // PR_MHS_COMMON_NAME
02697                     LIST_COPY_CONTACT_STR("MHS Common Name", item->contact->common_name);
02698                     break;
02699                 case 0x3A10: // PR_ORGANIZATIONAL_ID_NUMBER
02700                     LIST_COPY_CONTACT_STR("Organizational ID #", item->contact->org_id);
02701                     break;
02702                 case 0x3A11: // PR_SURNAME Contact's Surname
02703                     LIST_COPY_CONTACT_STR("Contacts Surname", item->contact->surname);
02704                     break;
02705                 case 0x3A12: // PR_ORIGINAL_ENTRY_ID
02706                     DEBUG_INFO(("Original Entry ID - NOT PROCESSED\n"));
02707                     break;
02708                 case 0x3A13: // PR_ORIGINAL_DISPLAY_NAME
02709                     DEBUG_INFO(("Original Display Name - NOT PROCESSED\n"));
02710                     break;
02711                 case 0x3A14: // PR_ORIGINAL_SEARCH_KEY
02712                     DEBUG_INFO(("Original Search Key - NOT PROCESSED\n"));
02713                     break;
02714                 case 0x3A15: // PR_POSTAL_ADDRESS
02715                     LIST_COPY_CONTACT_STR("Default Postal Address", item->contact->def_postal_address);
02716                     break;
02717                 case 0x3A16: // PR_COMPANY_NAME
02718                     LIST_COPY_CONTACT_STR("Company Name", item->contact->company_name);
02719                     break;
02720                 case 0x3A17: // PR_TITLE - Job Title
02721                     LIST_COPY_CONTACT_STR("Job Title", item->contact->job_title);
02722                     break;
02723                 case 0x3A18: // PR_DEPARTMENT_NAME
02724                     LIST_COPY_CONTACT_STR("Department Name", item->contact->department);
02725                     break;
02726                 case 0x3A19: // PR_OFFICE_LOCATION
02727                     LIST_COPY_CONTACT_STR("Office Location", item->contact->office_loc);
02728                     break;
02729                 case 0x3A1A: // PR_PRIMARY_TELEPHONE_NUMBER
02730                     LIST_COPY_CONTACT_STR("Primary Telephone", item->contact->primary_phone);
02731                     break;
02732                 case 0x3A1B: // PR_BUSINESS2_TELEPHONE_NUMBER
02733                     LIST_COPY_CONTACT_STR("Business Phone Number 2", item->contact->business_phone2);
02734                     break;
02735                 case 0x3A1C: // PR_MOBILE_TELEPHONE_NUMBER
02736                     LIST_COPY_CONTACT_STR("Mobile Phone Number", item->contact->mobile_phone);
02737                     break;
02738                 case 0x3A1D: // PR_RADIO_TELEPHONE_NUMBER
02739                     LIST_COPY_CONTACT_STR("Radio Phone Number", item->contact->radio_phone);
02740                     break;
02741                 case 0x3A1E: // PR_CAR_TELEPHONE_NUMBER
02742                     LIST_COPY_CONTACT_STR("Car Phone Number", item->contact->car_phone);
02743                     break;
02744                 case 0x3A1F: // PR_OTHER_TELEPHONE_NUMBER
02745                     LIST_COPY_CONTACT_STR("Other Phone Number", item->contact->other_phone);
02746                     break;
02747                 case 0x3A20: // PR_TRANSMITTABLE_DISPLAY_NAME
02748                     LIST_COPY_CONTACT_STR("Transmittable Display Name", item->contact->transmittable_display_name);
02749                     break;
02750                 case 0x3A21: // PR_PAGER_TELEPHONE_NUMBER
02751                     LIST_COPY_CONTACT_STR("Pager Phone Number", item->contact->pager_phone);
02752                     break;
02753                 case 0x3A22: // PR_USER_CERTIFICATE
02754                     DEBUG_INFO(("User Certificate - NOT PROCESSED\n"));
02755                     break;
02756                 case 0x3A23: // PR_PRIMARY_FAX_NUMBER
02757                     LIST_COPY_CONTACT_STR("Primary Fax Number", item->contact->primary_fax);
02758                     break;
02759                 case 0x3A24: // PR_BUSINESS_FAX_NUMBER
02760                     LIST_COPY_CONTACT_STR("Business Fax Number", item->contact->business_fax);
02761                     break;
02762                 case 0x3A25: // PR_HOME_FAX_NUMBER
02763                     LIST_COPY_CONTACT_STR("Home Fax Number", item->contact->home_fax);
02764                     break;
02765                 case 0x3A26: // PR_BUSINESS_ADDRESS_COUNTRY
02766                     LIST_COPY_CONTACT_STR("Business Address Country", item->contact->business_country);
02767                     break;
02768                 case 0x3A27: // PR_BUSINESS_ADDRESS_CITY
02769                     LIST_COPY_CONTACT_STR("Business Address City", item->contact->business_city);
02770                     break;
02771                 case 0x3A28: // PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE
02772                     LIST_COPY_CONTACT_STR("Business Address State", item->contact->business_state);
02773                     break;
02774                 case 0x3A29: // PR_BUSINESS_ADDRESS_STREET
02775                     LIST_COPY_CONTACT_STR("Business Address Street", item->contact->business_street);
02776                     break;
02777                 case 0x3A2A: // PR_BUSINESS_POSTAL_CODE
02778                     LIST_COPY_CONTACT_STR("Business Postal Code", item->contact->business_postal_code);
02779                     break;
02780                 case 0x3A2B: // PR_BUSINESS_PO_BOX
02781                     LIST_COPY_CONTACT_STR("Business PO Box", item->contact->business_po_box);
02782                     break;
02783                 case 0x3A2C: // PR_TELEX_NUMBER
02784                     LIST_COPY_CONTACT_STR("Telex Number", item->contact->telex);
02785                     break;
02786                 case 0x3A2D: // PR_ISDN_NUMBER
02787                     LIST_COPY_CONTACT_STR("ISDN Number", item->contact->isdn_phone);
02788                     break;
02789                 case 0x3A2E: // PR_ASSISTANT_TELEPHONE_NUMBER
02790                     LIST_COPY_CONTACT_STR("Assistant Phone Number", item->contact->assistant_phone);
02791                     break;
02792                 case 0x3A2F: // PR_HOME2_TELEPHONE_NUMBER
02793                     LIST_COPY_CONTACT_STR("Home Phone 2", item->contact->home_phone2);
02794                     break;
02795                 case 0x3A30: // PR_ASSISTANT
02796                     LIST_COPY_CONTACT_STR("Assistant's Name", item->contact->assistant_name);
02797                     break;
02798                 case 0x3A40: // PR_SEND_RICH_INFO
02799                     LIST_COPY_CONTACT_BOOL("Can receive Rich Text", item->contact->rich_text);
02800                     break;
02801                 case 0x3A41: // PR_WEDDING_ANNIVERSARY
02802                     LIST_COPY_CONTACT_TIME("Wedding Anniversary", item->contact->wedding_anniversary);
02803                     break;
02804                 case 0x3A42: // PR_BIRTHDAY
02805                     LIST_COPY_CONTACT_TIME("Birthday", item->contact->birthday);
02806                     break;
02807                 case 0x3A43: // PR_HOBBIES
02808                     LIST_COPY_CONTACT_STR("Hobbies", item->contact->hobbies);
02809                     break;
02810                 case 0x3A44: // PR_MIDDLE_NAME
02811                     LIST_COPY_CONTACT_STR("Middle Name", item->contact->middle_name);
02812                     break;
02813                 case 0x3A45: // PR_DISPLAY_NAME_PREFIX
02814                     LIST_COPY_CONTACT_STR("Display Name Prefix (Title)", item->contact->display_name_prefix);
02815                     break;
02816                 case 0x3A46: // PR_PROFESSION
02817                     LIST_COPY_CONTACT_STR("Profession", item->contact->profession);
02818                     break;
02819                 case 0x3A47: // PR_PREFERRED_BY_NAME
02820                     LIST_COPY_CONTACT_STR("Preferred By Name", item->contact->pref_name);
02821                     break;
02822                 case 0x3A48: // PR_SPOUSE_NAME
02823                     LIST_COPY_CONTACT_STR("Spouse's Name", item->contact->spouse_name);
02824                     break;
02825                 case 0x3A49: // PR_COMPUTER_NETWORK_NAME
02826                     LIST_COPY_CONTACT_STR("Computer Network Name", item->contact->computer_name);
02827                     break;
02828                 case 0x3A4A: // PR_CUSTOMER_ID
02829                     LIST_COPY_CONTACT_STR("Customer ID", item->contact->customer_id);
02830                     break;
02831                 case 0x3A4B: // PR_TTYTDD_PHONE_NUMBER
02832                     LIST_COPY_CONTACT_STR("TTY/TDD Phone", item->contact->ttytdd_phone);
02833                     break;
02834                 case 0x3A4C: // PR_FTP_SITE
02835                     LIST_COPY_CONTACT_STR("Ftp Site", item->contact->ftp_site);
02836                     break;
02837                 case 0x3A4D: // PR_GENDER
02838                     LIST_COPY_CONTACT_ENUM16("Gender", item->contact->gender, 0, 3, "Unspecified", "Female", "Male");
02839                     break;
02840                 case 0x3A4E: // PR_MANAGER_NAME
02841                     LIST_COPY_CONTACT_STR("Manager's Name", item->contact->manager_name);
02842                     break;
02843                 case 0x3A4F: // PR_NICKNAME
02844                     LIST_COPY_CONTACT_STR("Nickname", item->contact->nickname);
02845                     break;
02846                 case 0x3A50: // PR_PERSONAL_HOME_PAGE
02847                     LIST_COPY_CONTACT_STR("Personal Home Page", item->contact->personal_homepage);
02848                     break;
02849                 case 0x3A51: // PR_BUSINESS_HOME_PAGE
02850                     LIST_COPY_CONTACT_STR("Business Home Page", item->contact->business_homepage);
02851                     break;
02852                 case 0x3A57: // PR_COMPANY_MAIN_PHONE_NUMBER
02853                     LIST_COPY_CONTACT_STR("Company Main Phone", item->contact->company_main_phone);
02854                     break;
02855                 case 0x3A58: // PR_CHILDRENS_NAMES
02856                     DEBUG_INFO(("Children's Names - NOT PROCESSED\n"));
02857                     break;
02858                 case 0x3A59: // PR_HOME_ADDRESS_CITY
02859                     LIST_COPY_CONTACT_STR("Home Address City", item->contact->home_city);
02860                     break;
02861                 case 0x3A5A: // PR_HOME_ADDRESS_COUNTRY
02862                     LIST_COPY_CONTACT_STR("Home Address Country", item->contact->home_country);
02863                     break;
02864                 case 0x3A5B: // PR_HOME_ADDRESS_POSTAL_CODE
02865                     LIST_COPY_CONTACT_STR("Home Address Postal Code", item->contact->home_postal_code);
02866                     break;
02867                 case 0x3A5C: // PR_HOME_ADDRESS_STATE_OR_PROVINCE
02868                     LIST_COPY_CONTACT_STR("Home Address State or Province", item->contact->home_state);
02869                     break;
02870                 case 0x3A5D: // PR_HOME_ADDRESS_STREET
02871                     LIST_COPY_CONTACT_STR("Home Address Street", item->contact->home_street);
02872                     break;
02873                 case 0x3A5E: // PR_HOME_ADDRESS_POST_OFFICE_BOX
02874                     LIST_COPY_CONTACT_STR("Home Address Post Office Box", item->contact->home_po_box);
02875                     break;
02876                 case 0x3A5F: // PR_OTHER_ADDRESS_CITY
02877                     LIST_COPY_CONTACT_STR("Other Address City", item->contact->other_city);
02878                     break;
02879                 case 0x3A60: // PR_OTHER_ADDRESS_COUNTRY
02880                     LIST_COPY_CONTACT_STR("Other Address Country", item->contact->other_country);
02881                     break;
02882                 case 0x3A61: // PR_OTHER_ADDRESS_POSTAL_CODE
02883                     LIST_COPY_CONTACT_STR("Other Address Postal Code", item->contact->other_postal_code);
02884                     break;
02885                 case 0x3A62: // PR_OTHER_ADDRESS_STATE_OR_PROVINCE
02886                     LIST_COPY_CONTACT_STR("Other Address State", item->contact->other_state);
02887                     break;
02888                 case 0x3A63: // PR_OTHER_ADDRESS_STREET
02889                     LIST_COPY_CONTACT_STR("Other Address Street", item->contact->other_street);
02890                     break;
02891                 case 0x3A64: // PR_OTHER_ADDRESS_POST_OFFICE_BOX
02892                     LIST_COPY_CONTACT_STR("Other Address Post Office box", item->contact->other_po_box);
02893                     break;
02894                 case 0x3FDE: // PR_INTERNET_CPID
02895                     LIST_COPY_INT32("Internet code page", item->internet_cpid);
02896                     break;
02897                 case 0x3FFD: // PR_MESSAGE_CODEPAGE
02898                     LIST_COPY_INT32("Message code page", item->message_codepage);
02899                     break;
02900                 case 0x65E3: // PR_PREDECESSOR_CHANGE_LIST
02901                     LIST_COPY_BIN(item->predecessor_change);
02902                     DEBUG_INFO(("Predecessor Change\n"));
02903                     DEBUG_HEXDUMP(item->predecessor_change.data, item->predecessor_change.size);
02904                     break;
02905                 case 0x67F2: // ID2 value of the attachment
02906                     NULL_CHECK(attach);
02907                     LIST_COPY_INT32("Attachment ID2 value", ut);
02908                     attach->id2_val = ut;
02909                     break;
02910                 case 0x67FF: // Extra Property Identifier (Password CheckSum)
02911                     LIST_COPY_STORE_INT32("Password checksum", item->message_store->pwd_chksum);
02912                     break;
02913                 case 0x6F02: // Secure HTML Body
02914                     LIST_COPY_EMAIL_BIN("Secure HTML Body", item->email->encrypted_htmlbody);
02915                     break;
02916                 case 0x6F04: // Secure Text Body
02917                     LIST_COPY_EMAIL_BIN("Secure Text Body", item->email->encrypted_body);
02918                     break;
02919                 case 0x7C07: // top of folders ENTRYID
02920                     LIST_COPY_STORE_ENTRYID("Top of folders RecID", item->message_store->top_of_folder);
02921                     break;
02922                 case 0x8005: // Contact's Fullname
02923                     LIST_COPY_CONTACT_STR("Contact Fullname", item->contact->fullname);
02924                     break;
02925                 case 0x801A: // Full Home Address
02926                     LIST_COPY_CONTACT_STR("Home Address", item->contact->home_address);
02927                     break;
02928                 case 0x801B: // Full Business Address
02929                     LIST_COPY_CONTACT_STR("Business Address", item->contact->business_address);
02930                     break;
02931                 case 0x801C: // Full Other Address
02932                     LIST_COPY_CONTACT_STR("Other Address", item->contact->other_address);
02933                     break;
02934                 case 0x8045: // Work address street
02935                     LIST_COPY_CONTACT_STR("Work address street", item->contact->work_address_street);
02936                     break;
02937                 case 0x8046: // Work address city
02938                     LIST_COPY_CONTACT_STR("Work address city", item->contact->work_address_city);
02939                     break;
02940                 case 0x8047: // Work address state
02941                     LIST_COPY_CONTACT_STR("Work address state", item->contact->work_address_state);
02942                     break;
02943                 case 0x8048: // Work address postalcode
02944                     LIST_COPY_CONTACT_STR("Work address postalcode", item->contact->work_address_postalcode);
02945                     break;
02946                 case 0x8049: // Work address country
02947                     LIST_COPY_CONTACT_STR("Work address country", item->contact->work_address_country);
02948                     break;
02949                 case 0x804A: // Work address postofficebox
02950                     LIST_COPY_CONTACT_STR("Work address postofficebox", item->contact->work_address_postofficebox);
02951                     break;
02952                 case 0x8082: // Email Address 1 Transport
02953                     LIST_COPY_CONTACT_STR("Email Address 1 Transport", item->contact->address1_transport);
02954                     break;
02955                 case 0x8083: // Email Address 1 Address
02956                     LIST_COPY_CONTACT_STR("Email Address 1 Address", item->contact->address1);
02957                     break;
02958                 case 0x8084: // Email Address 1 Description
02959                     LIST_COPY_CONTACT_STR("Email Address 1 Description", item->contact->address1_desc);
02960                     break;
02961                 case 0x8085: // Email Address 1 Record
02962                     LIST_COPY_CONTACT_STR("Email Address 1 Record", item->contact->address1a);
02963                     break;
02964                 case 0x8092: // Email Address 2 Transport
02965                     LIST_COPY_CONTACT_STR("Email Address 2 Transport", item->contact->address2_transport);
02966                     break;
02967                 case 0x8093: // Email Address 2 Address
02968                     LIST_COPY_CONTACT_STR("Email Address 2 Address", item->contact->address2);
02969                     break;
02970                 case 0x8094: // Email Address 2 Description
02971                     LIST_COPY_CONTACT_STR("Email Address 2 Description", item->contact->address2_desc);
02972                     break;
02973                 case 0x8095: // Email Address 2 Record
02974                     LIST_COPY_CONTACT_STR("Email Address 2 Record", item->contact->address2a);
02975                     break;
02976                 case 0x80A2: // Email Address 3 Transport
02977                     LIST_COPY_CONTACT_STR("Email Address 3 Transport", item->contact->address3_transport);
02978                     break;
02979                 case 0x80A3: // Email Address 3 Address
02980                     LIST_COPY_CONTACT_STR("Email Address 3 Address", item->contact->address3);
02981                     break;
02982                 case 0x80A4: // Email Address 3 Description
02983                     LIST_COPY_CONTACT_STR("Email Address 3 Description", item->contact->address3_desc);
02984                     break;
02985                 case 0x80A5: // Email Address 3 Record
02986                     LIST_COPY_CONTACT_STR("Email Address 3 Record", item->contact->address3a);
02987                     break;
02988                 case 0x80D8: // Internet Free/Busy
02989                     LIST_COPY_CONTACT_STR("Internet Free/Busy", item->contact->free_busy_address);
02990                     break;
02991                 case 0x8205: // PR_OUTLOOK_EVENT_SHOW_TIME_AS
02992                     LIST_COPY_APPT_ENUM("Appointment shows as", item->appointment->showas, 0, 4,
02993                         "Free", "Tentative", "Busy", "Out Of Office");
02994                     break;
02995                 case 0x8208: // PR_OUTLOOK_EVENT_LOCATION
02996                     LIST_COPY_APPT_STR("Appointment Location", item->appointment->location);
02997                     break;
02998                 case 0x820d: // PR_OUTLOOK_EVENT_START_DATE
02999                     LIST_COPY_APPT_TIME("Appointment Date Start", item->appointment->start);
03000                     break;
03001                 case 0x820e: // PR_OUTLOOK_EVENT_START_END
03002                     LIST_COPY_APPT_TIME("Appointment Date End", item->appointment->end);
03003                     break;
03004                 case 0x8214: // Label for an appointment
03005                     LIST_COPY_APPT_ENUM("Label for appointment", item->appointment->label, 0, 11,
03006                         "None",
03007                         "Important",
03008                         "Business",
03009                         "Personal",
03010                         "Vacation",
03011                         "Must Attend",
03012                         "Travel Required",
03013                         "Needs Preparation",
03014                         "Birthday",
03015                         "Anniversary",
03016                         "Phone Call");
03017                     break;
03018                 case 0x8215: // PR_OUTLOOK_EVENT_ALL_DAY
03019                     LIST_COPY_APPT_BOOL("All day flag", item->appointment->all_day);
03020                     break;
03021                 case 0x8216: // PR_OUTLOOK_EVENT_RECURRENCE_DATA
03022                     LIST_COPY_APPT_BIN("Appointment recurrence data", item->appointment->recurrence_data);
03023                     break;
03024                 case 0x8223: // PR_OUTLOOK_EVENT_IS_RECURRING
03025                     LIST_COPY_APPT_BOOL("Is recurring", item->appointment->is_recurring);
03026                     break;
03027                 case 0x8231: // Recurrence type
03028                     LIST_COPY_APPT_ENUM("Appointment recurrence type ", item->appointment->recurrence_type, 0, 5,
03029                         "None",
03030                         "Daily",
03031                         "Weekly",
03032                         "Monthly",
03033                         "Yearly");
03034                     break;
03035                 case 0x8232: // Recurrence description
03036                     LIST_COPY_APPT_STR("Appointment recurrence description", item->appointment->recurrence_description);
03037                     break;
03038                 case 0x8234: // TimeZone as String
03039                     LIST_COPY_APPT_STR("TimeZone of times", item->appointment->timezonestring);
03040                     break;
03041                 case 0x8235: // PR_OUTLOOK_EVENT_RECURRENCE_START
03042                     LIST_COPY_APPT_TIME("Recurrence Start Date", item->appointment->recurrence_start);
03043                     break;
03044                 case 0x8236: // PR_OUTLOOK_EVENT_RECURRENCE_END
03045                     LIST_COPY_APPT_TIME("Recurrence End Date", item->appointment->recurrence_end);
03046                     break;
03047                 case 0x8501: // PR_OUTLOOK_COMMON_REMINDER_MINUTES_BEFORE
03048                     LIST_COPY_APPT_INT32("Alarm minutes", item->appointment->alarm_minutes);
03049                     break;
03050                 case 0x8503: // PR_OUTLOOK_COMMON_REMINDER_SET
03051                     LIST_COPY_APPT_BOOL("Reminder alarm", item->appointment->alarm);
03052                     break;
03053                 case 0x8516: // Common start
03054                     DEBUG_INFO(("Common Start Date - %s\n", pst_fileTimeToAscii((FILETIME*)list->elements[x]->data, time_buffer)));
03055                     break;
03056                 case 0x8517: // Common end
03057                     DEBUG_INFO(("Common End Date - %s\n", pst_fileTimeToAscii((FILETIME*)list->elements[x]->data, time_buffer)));
03058                     break;
03059                 case 0x851f: // Play reminder sound filename
03060                     LIST_COPY_APPT_STR("Appointment reminder sound filename", item->appointment->alarm_filename);
03061                     break;
03062                 case 0x8530: // Followup
03063                     LIST_COPY_CONTACT_STR("Followup String", item->contact->followup);
03064                     break;
03065                 case 0x8534: // Mileage
03066                     LIST_COPY_CONTACT_STR("Mileage", item->contact->mileage);
03067                     break;
03068                 case 0x8535: // Billing Information
03069                     LIST_COPY_CONTACT_STR("Billing Information", item->contact->billing_information);
03070                     break;
03071                 case 0x8554: // PR_OUTLOOK_VERSION
03072                     LIST_COPY_STR("Outlook Version", item->outlook_version);
03073                     break;
03074                 case 0x8560: // Appointment Reminder Time
03075                     LIST_COPY_APPT_TIME("Appointment Reminder Time", item->appointment->reminder);
03076                     break;
03077                 case 0x8700: // Journal Type
03078                     LIST_COPY_JOURNAL_STR("Journal Entry Type", item->journal->type);
03079                     break;
03080                 case 0x8706: // Journal Start date/time
03081                     LIST_COPY_JOURNAL_TIME("Start Timestamp", item->journal->start);
03082                     break;
03083                 case 0x8708: // Journal End date/time
03084                     LIST_COPY_JOURNAL_TIME("End Timestamp", item->journal->end);
03085                     break;
03086                 case 0x8712: // Journal Type Description
03087                     LIST_COPY_JOURNAL_STR("Journal description", item->journal->description);
03088                     break;
03089                 default:
03090                     if (list->elements[x]->type == (uint32_t)0x0002) {
03091                         DEBUG_WARN(("Unknown type %#x 16bit int = %hi\n", list->elements[x]->mapi_id,
03092                             *(int16_t*)list->elements[x]->data));
03093 
03094                     } else if (list->elements[x]->type == (uint32_t)0x0003) {
03095                         DEBUG_WARN(("Unknown type %#x 32bit int = %i\n", list->elements[x]->mapi_id,
03096                             *(int32_t*)list->elements[x]->data));
03097 
03098                     } else if (list->elements[x]->type == (uint32_t)0x0004) {
03099                         DEBUG_WARN(("Unknown type %#x 4-byte floating [size = %#x]\n", list->elements[x]->mapi_id,
03100                             list->elements[x]->size));
03101                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03102 
03103                     } else if (list->elements[x]->type == (uint32_t)0x0005) {
03104                         DEBUG_WARN(("Unknown type %#x double floating [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)0x0006) {
03109                         DEBUG_WARN(("Unknown type %#x signed 64bit int = %"PRIi64"\n", list->elements[x]->mapi_id,
03110                             *(int64_t*)list->elements[x]->data));
03111                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03112 
03113                     } else if (list->elements[x]->type == (uint32_t)0x0007) {
03114                         DEBUG_WARN(("Unknown type %#x application time [size = %#x]\n", list->elements[x]->mapi_id,
03115                             list->elements[x]->size));
03116                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03117 
03118                     } else if (list->elements[x]->type == (uint32_t)0x000a) {
03119                         DEBUG_WARN(("Unknown type %#x 32bit error value = %i\n", list->elements[x]->mapi_id,
03120                             *(int32_t*)list->elements[x]->data));
03121 
03122                     } else if (list->elements[x]->type == (uint32_t)0x000b) {
03123                         DEBUG_WARN(("Unknown type %#x 16bit boolean = %s [%hi]\n", list->elements[x]->mapi_id,
03124                             (*((int16_t*)list->elements[x]->data)!=0?"True":"False"),
03125                             *((int16_t*)list->elements[x]->data)));
03126 
03127                     } else if (list->elements[x]->type == (uint32_t)0x000d) {
03128                         DEBUG_WARN(("Unknown type %#x Embedded object [size = %#x]\n", list->elements[x]->mapi_id,
03129                             list->elements[x]->size));
03130                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03131 
03132                     } else if (list->elements[x]->type == (uint32_t)0x0014) {
03133                         DEBUG_WARN(("Unknown type %#x signed 64bit int = %"PRIi64"\n", list->elements[x]->mapi_id,
03134                             *(int64_t*)list->elements[x]->data));
03135                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03136 
03137                     } else if (list->elements[x]->type == (uint32_t)0x001e) {
03138                         DEBUG_WARN(("Unknown type %#x String Data = \"%s\"\n", list->elements[x]->mapi_id,
03139                             list->elements[x]->data));
03140 
03141                     } else if (list->elements[x]->type == (uint32_t)0x001f) {
03142                         DEBUG_WARN(("Unknown type %#x Unicode String Data [size = %#x]\n", list->elements[x]->mapi_id,
03143                             list->elements[x]->size));
03144                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03145 
03146                     } else if (list->elements[x]->type == (uint32_t)0x0040) {
03147                         DEBUG_WARN(("Unknown type %#x Date = \"%s\"\n", list->elements[x]->mapi_id,
03148                             pst_fileTimeToAscii((FILETIME*)list->elements[x]->data, time_buffer)));
03149 
03150                     } else if (list->elements[x]->type == (uint32_t)0x0048) {
03151                         DEBUG_WARN(("Unknown type %#x OLE GUID [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)0x0102) {
03156                         DEBUG_WARN(("Unknown type %#x Binary Data [size = %#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)0x1003) {
03161                         DEBUG_WARN(("Unknown type %#x Array of 32 bit values [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)0x1014) {
03166                         DEBUG_WARN(("Unknown type %#x Array of 64 bit values [siize = %#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)0x101e) {
03171                         DEBUG_WARN(("Unknown type %#x Array of Strings [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 if (list->elements[x]->type == (uint32_t)0x101f) {
03176                         DEBUG_WARN(("Unknown type %#x Array of Unicode Strings [size = %#x]\n", list->elements[x]->mapi_id,
03177                             list->elements[x]->size));
03178                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03179 
03180                     } else if (list->elements[x]->type == (uint32_t)0x1102) {
03181                         DEBUG_WARN(("Unknown type %#x Array of binary data blobs [size = %#x]\n", list->elements[x]->mapi_id,
03182                             list->elements[x]->size));
03183                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03184 
03185                     } else {
03186                         DEBUG_WARN(("Unknown type %#x Not Printable [%#x]\n", list->elements[x]->mapi_id,
03187                             list->elements[x]->type));
03188                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
03189                     }
03190 
03191                     if (list->elements[x]->data) {
03192                         free(list->elements[x]->data);
03193                         list->elements[x]->data = NULL;
03194                     }
03195             }
03196         }
03197         list = list->next;
03198         if (attach) attach = attach->next;
03199     }
03200     DEBUG_RET();
03201     return 0;
03202 }
03203 
03204 
03205 static void pst_free_list(pst_mapi_object *list) {
03206     pst_mapi_object *l;
03207     DEBUG_ENT("pst_free_list");
03208     while (list) {
03209         if (list->elements) {
03210             int32_t x;
03211             for (x=0; x < list->orig_count; x++) {
03212                 if (list->elements[x]) {
03213                     if (list->elements[x]->data) free(list->elements[x]->data);
03214                     free(list->elements[x]);
03215                 }
03216             }
03217             free(list->elements);
03218         }
03219         l = list->next;
03220         free (list);
03221         list = l;
03222     }
03223     DEBUG_RET();
03224 }
03225 
03226 
03227 static void pst_free_id2(pst_id2_tree * head) {
03228     pst_id2_tree *t;
03229     DEBUG_ENT("pst_free_id2");
03230     while (head) {
03231         pst_free_id2(head->child);
03232         t = head->next;
03233         free(head);
03234         head = t;
03235     }
03236     DEBUG_RET();
03237 }
03238 
03239 
03240 static void pst_free_id (pst_index_ll *head) {
03241     pst_index_ll *t;
03242     DEBUG_ENT("pst_free_id");
03243     while (head) {
03244         t = head->next;
03245         free(head);
03246         head = t;
03247     }
03248     DEBUG_RET();
03249 }
03250 
03251 
03252 static void pst_free_desc (pst_desc_tree *head) {
03253     pst_desc_tree *t;
03254     DEBUG_ENT("pst_free_desc");
03255     while (head) {
03256         pst_free_desc(head->child);
03257         t = head->next;
03258         free(head);
03259         head = t;
03260     }
03261     DEBUG_RET();
03262 }
03263 
03264 
03265 static void pst_free_xattrib(pst_x_attrib_ll *x) {
03266     pst_x_attrib_ll *t;
03267     DEBUG_ENT("pst_free_xattrib");
03268     while (x) {
03269         if (x->data) free(x->data);
03270         t = x->next;
03271         free(x);
03272         x = t;
03273     }
03274     DEBUG_RET();
03275 }
03276 
03277 
03278 static pst_id2_tree * pst_build_id2(pst_file *pf, pst_index_ll* list) {
03279     pst_block_header block_head;
03280     pst_id2_tree *head = NULL, *tail = NULL;
03281     uint16_t x = 0;
03282     char *b_ptr = NULL;
03283     char *buf = NULL;
03284     pst_id2_assoc id2_rec;
03285     pst_index_ll *i_ptr = NULL;
03286     pst_id2_tree *i2_ptr = NULL;
03287     DEBUG_ENT("pst_build_id2");
03288 
03289     if (pst_read_block_size(pf, list->offset, list->size, &buf) < list->size) {
03290         //an error occured in block read
03291         DEBUG_WARN(("block read error occured. offset = %#"PRIx64", size = %#"PRIx64"\n", list->offset, list->size));
03292         if (buf) free(buf);
03293         DEBUG_RET();
03294         return NULL;
03295     }
03296     DEBUG_HEXDUMPC(buf, list->size, 16);
03297 
03298     memcpy(&block_head, buf, sizeof(block_head));
03299     LE16_CPU(block_head.type);
03300     LE16_CPU(block_head.count);
03301 
03302     if (block_head.type != (uint16_t)0x0002) { // some sort of constant?
03303         DEBUG_WARN(("Unknown constant [%#hx] at start of id2 values [offset %#"PRIx64"].\n", block_head.type, list->offset));
03304         if (buf) free(buf);
03305         DEBUG_RET();
03306         return NULL;
03307     }
03308 
03309     DEBUG_INFO(("ID %#"PRIx64" is likely to be a description record. Count is %i (offset %#"PRIx64")\n",
03310             list->i_id, block_head.count, list->offset));
03311     x = 0;
03312     b_ptr = buf + ((pf->do_read64) ? 0x08 : 0x04);
03313     while (x < block_head.count) {
03314         b_ptr += pst_decode_assoc(pf, &id2_rec, b_ptr);
03315         DEBUG_INFO(("id2 = %#x, id = %#"PRIx64", child id = %#"PRIx64"\n", id2_rec.id2, id2_rec.id, id2_rec.child_id));
03316         if ((i_ptr = pst_getID(pf, id2_rec.id)) == NULL) {
03317             DEBUG_WARN(("%#"PRIx64" - Not Found\n", id2_rec.id));
03318         } else {
03319             DEBUG_INFO(("%#"PRIx64" - Offset %#"PRIx64", u1 %#"PRIx64", Size %"PRIi64"(%#"PRIx64")\n",
03320                          i_ptr->i_id, i_ptr->offset, i_ptr->u1, i_ptr->size, i_ptr->size));
03321             // add it to the tree
03322             i2_ptr = (pst_id2_tree*) pst_malloc(sizeof(pst_id2_tree));
03323             i2_ptr->id2   = id2_rec.id2;
03324             i2_ptr->id    = i_ptr;
03325             i2_ptr->child = NULL;
03326             i2_ptr->next  = NULL;
03327             if (!head) head = i2_ptr;
03328             if (tail)  tail->next = i2_ptr;
03329             tail = i2_ptr;
03330             if (id2_rec.child_id) {
03331                 if ((i_ptr = pst_getID(pf, id2_rec.child_id)) == NULL) {
03332                     DEBUG_WARN(("child id [%#"PRIx64"] not found\n", id2_rec.child_id));
03333                 }
03334                 else {
03335                     i2_ptr->child = pst_build_id2(pf, i_ptr);
03336                 }
03337             }
03338         }
03339         x++;
03340     }
03341     if (buf) free (buf);
03342     DEBUG_RET();
03343     return head;
03344 }
03345 
03346 
03347 static void pst_free_attach(pst_item_attach *attach) {
03348     while (attach) {
03349         pst_item_attach *t;
03350         SAFE_FREE_STR(attach->filename1);
03351         SAFE_FREE_STR(attach->filename2);
03352         SAFE_FREE_STR(attach->mimetype);
03353         SAFE_FREE_STR(attach->content_id);
03354         SAFE_FREE_BIN(attach->data);
03355         pst_free_id2(attach->id2_head);
03356         t = attach->next;
03357         free(attach);
03358         attach = t;
03359     }
03360 }
03361 
03362 
03363 void pst_freeItem(pst_item *item) {
03364     pst_item_extra_field *et;
03365 
03366     DEBUG_ENT("pst_freeItem");
03367     if (item) {
03368         if (item->email) {
03369             SAFE_FREE(item->email->arrival_date);
03370             SAFE_FREE_STR(item->email->cc_address);
03371             SAFE_FREE_STR(item->email->bcc_address);
03372             SAFE_FREE_BIN(item->email->conversation_index);
03373             SAFE_FREE_BIN(item->email->encrypted_body);
03374             SAFE_FREE_BIN(item->email->encrypted_htmlbody);
03375             SAFE_FREE_STR(item->email->header);
03376             SAFE_FREE_STR(item->email->htmlbody);
03377             SAFE_FREE_STR(item->email->in_reply_to);
03378             SAFE_FREE_STR(item->email->messageid);
03379             SAFE_FREE_STR(item->email->original_bcc);
03380             SAFE_FREE_STR(item->email->original_cc);
03381             SAFE_FREE_STR(item->email->original_to);
03382             SAFE_FREE_STR(item->email->outlook_recipient);
03383             SAFE_FREE_STR(item->email->outlook_recipient_name);
03384             SAFE_FREE_STR(item->email->outlook_recipient2);
03385             SAFE_FREE_STR(item->email->outlook_sender);
03386             SAFE_FREE_STR(item->email->outlook_sender_name);
03387             SAFE_FREE_STR(item->email->outlook_sender2);
03388             SAFE_FREE_STR(item->email->processed_subject);
03389             SAFE_FREE_STR(item->email->recip_access);
03390             SAFE_FREE_STR(item->email->recip_address);
03391             SAFE_FREE_STR(item->email->recip2_access);
03392             SAFE_FREE_STR(item->email->recip2_address);
03393             SAFE_FREE_STR(item->email->reply_to);
03394             SAFE_FREE_STR(item->email->rtf_body_tag);
03395             SAFE_FREE_BIN(item->email->rtf_compressed);
03396             SAFE_FREE_STR(item->email->return_path_address);
03397             SAFE_FREE_STR(item->email->sender_access);
03398             SAFE_FREE_STR(item->email->sender_address);
03399             SAFE_FREE_STR(item->email->sender2_access);
03400             SAFE_FREE_STR(item->email->sender2_address);
03401             SAFE_FREE(item->email->sent_date);
03402             SAFE_FREE(item->email->sentmail_folder);
03403             SAFE_FREE_STR(item->email->sentto_address);
03404             SAFE_FREE_STR(item->email->report_text);
03405             SAFE_FREE(item->email->report_time);
03406             SAFE_FREE_STR(item->email->supplementary_info);
03407             SAFE_FREE_STR(item->email->outlook_received_name1);
03408             SAFE_FREE_STR(item->email->outlook_sender_name2);
03409             SAFE_FREE_STR(item->email->outlook_normalized_subject);
03410             SAFE_FREE_STR(item->email->outlook_search_key);
03411             free(item->email);
03412         }
03413         if (item->folder) {
03414             free(item->folder);
03415         }
03416         if (item->message_store) {
03417             SAFE_FREE(item->message_store->top_of_personal_folder);
03418             SAFE_FREE(item->message_store->default_outbox_folder);
03419             SAFE_FREE(item->message_store->deleted_items_folder);
03420             SAFE_FREE(item->message_store->sent_items_folder);
03421             SAFE_FREE(item->message_store->user_views_folder);
03422             SAFE_FREE(item->message_store->common_view_folder);
03423             SAFE_FREE(item->message_store->search_root_folder);
03424             SAFE_FREE(item->message_store->top_of_folder);
03425             free(item->message_store);
03426         }
03427         if (item->contact) {
03428             SAFE_FREE_STR(item->contact->account_name);
03429             SAFE_FREE_STR(item->contact->address1);
03430             SAFE_FREE_STR(item->contact->address1a);
03431             SAFE_FREE_STR(item->contact->address1_desc);
03432             SAFE_FREE_STR(item->contact->address1_transport);
03433             SAFE_FREE_STR(item->contact->address2);
03434             SAFE_FREE_STR(item->contact->address2a);
03435             SAFE_FREE_STR(item->contact->address2_desc);
03436             SAFE_FREE_STR(item->contact->address2_transport);
03437             SAFE_FREE_STR(item->contact->address3);
03438             SAFE_FREE_STR(item->contact->address3a);
03439             SAFE_FREE_STR(item->contact->address3_desc);
03440             SAFE_FREE_STR(item->contact->address3_transport);
03441             SAFE_FREE_STR(item->contact->assistant_name);
03442             SAFE_FREE_STR(item->contact->assistant_phone);
03443             SAFE_FREE_STR(item->contact->billing_information);
03444             SAFE_FREE(item->contact->birthday);
03445             SAFE_FREE_STR(item->contact->business_address);
03446             SAFE_FREE_STR(item->contact->business_city);
03447             SAFE_FREE_STR(item->contact->business_country);
03448             SAFE_FREE_STR(item->contact->business_fax);
03449             SAFE_FREE_STR(item->contact->business_homepage);
03450             SAFE_FREE_STR(item->contact->business_phone);
03451             SAFE_FREE_STR(item->contact->business_phone2);
03452             SAFE_FREE_STR(item->contact->business_po_box);
03453             SAFE_FREE_STR(item->contact->business_postal_code);
03454             SAFE_FREE_STR(item->contact->business_state);
03455             SAFE_FREE_STR(item->contact->business_street);
03456             SAFE_FREE_STR(item->contact->callback_phone);
03457             SAFE_FREE_STR(item->contact->car_phone);
03458             SAFE_FREE_STR(item->contact->company_main_phone);
03459             SAFE_FREE_STR(item->contact->company_name);
03460             SAFE_FREE_STR(item->contact->computer_name);
03461             SAFE_FREE_STR(item->contact->customer_id);
03462             SAFE_FREE_STR(item->contact->def_postal_address);
03463             SAFE_FREE_STR(item->contact->department);
03464             SAFE_FREE_STR(item->contact->display_name_prefix);
03465             SAFE_FREE_STR(item->contact->first_name);
03466             SAFE_FREE_STR(item->contact->followup);
03467             SAFE_FREE_STR(item->contact->free_busy_address);
03468             SAFE_FREE_STR(item->contact->ftp_site);
03469             SAFE_FREE_STR(item->contact->fullname);
03470             SAFE_FREE_STR(item->contact->gov_id);
03471             SAFE_FREE_STR(item->contact->hobbies);
03472             SAFE_FREE_STR(item->contact->home_address);
03473             SAFE_FREE_STR(item->contact->home_city);
03474             SAFE_FREE_STR(item->contact->home_country);
03475             SAFE_FREE_STR(item->contact->home_fax);
03476             SAFE_FREE_STR(item->contact->home_po_box);
03477             SAFE_FREE_STR(item->contact->home_phone);
03478             SAFE_FREE_STR(item->contact->home_phone2);
03479             SAFE_FREE_STR(item->contact->home_postal_code);
03480             SAFE_FREE_STR(item->contact->home_state);
03481             SAFE_FREE_STR(item->contact->home_street);
03482             SAFE_FREE_STR(item->contact->initials);
03483             SAFE_FREE_STR(item->contact->isdn_phone);
03484             SAFE_FREE_STR(item->contact->job_title);
03485             SAFE_FREE_STR(item->contact->keyword);
03486             SAFE_FREE_STR(item->contact->language);
03487             SAFE_FREE_STR(item->contact->location);
03488             SAFE_FREE_STR(item->contact->manager_name);
03489             SAFE_FREE_STR(item->contact->middle_name);
03490             SAFE_FREE_STR(item->contact->mileage);
03491             SAFE_FREE_STR(item->contact->mobile_phone);
03492             SAFE_FREE_STR(item->contact->nickname);
03493             SAFE_FREE_STR(item->contact->office_loc);
03494             SAFE_FREE_STR(item->contact->common_name);
03495             SAFE_FREE_STR(item->contact->org_id);
03496             SAFE_FREE_STR(item->contact->other_address);
03497             SAFE_FREE_STR(item->contact->other_city);
03498             SAFE_FREE_STR(item->contact->other_country);
03499             SAFE_FREE_STR(item->contact->other_phone);
03500             SAFE_FREE_STR(item->contact->other_po_box);
03501             SAFE_FREE_STR(item->contact->other_postal_code);
03502             SAFE_FREE_STR(item->contact->other_state);
03503             SAFE_FREE_STR(item->contact->other_street);
03504             SAFE_FREE_STR(item->contact->pager_phone);
03505             SAFE_FREE_STR(item->contact->personal_homepage);
03506             SAFE_FREE_STR(item->contact->pref_name);
03507             SAFE_FREE_STR(item->contact->primary_fax);
03508             SAFE_FREE_STR(item->contact->primary_phone);
03509             SAFE_FREE_STR(item->contact->profession);
03510             SAFE_FREE_STR(item->contact->radio_phone);
03511             SAFE_FREE_STR(item->contact->spouse_name);
03512             SAFE_FREE_STR(item->contact->suffix);
03513             SAFE_FREE_STR(item->contact->surname);
03514             SAFE_FREE_STR(item->contact->telex);
03515             SAFE_FREE_STR(item->contact->transmittable_display_name);
03516             SAFE_FREE_STR(item->contact->ttytdd_phone);
03517             SAFE_FREE(item->contact->wedding_anniversary);
03518             SAFE_FREE_STR(item->contact->work_address_street);
03519             SAFE_FREE_STR(item->contact->work_address_city);
03520             SAFE_FREE_STR(item->contact->work_address_state);
03521             SAFE_FREE_STR(item->contact->work_address_postalcode);
03522             SAFE_FREE_STR(item->contact->work_address_country);
03523             SAFE_FREE_STR(item->contact->work_address_postofficebox);
03524             free(item->contact);
03525         }
03526 
03527         pst_free_attach(item->attach);
03528 
03529         while (item->extra_fields) {
03530             SAFE_FREE(item->extra_fields->field_name);
03531             SAFE_FREE(item->extra_fields->value);
03532             et = item->extra_fields->next;
03533             free(item->extra_fields);
03534             item->extra_fields = et;
03535         }
03536         if (item->journal) {
03537             SAFE_FREE(item->journal->start);
03538             SAFE_FREE(item->journal->end);
03539             SAFE_FREE_STR(item->journal->type);
03540             free(item->journal);
03541         }
03542         if (item->appointment) {
03543             SAFE_FREE(item->appointment->start);
03544             SAFE_FREE(item->appointment->end);
03545             SAFE_FREE_STR(item->appointment->location);
03546             SAFE_FREE(item->appointment->reminder);
03547             SAFE_FREE_STR(item->appointment->alarm_filename);
03548             SAFE_FREE_STR(item->appointment->timezonestring);
03549             SAFE_FREE_STR(item->appointment->recurrence_description);
03550             SAFE_FREE_BIN(item->appointment->recurrence_data);
03551             SAFE_FREE(item->appointment->recurrence_start);
03552             SAFE_FREE(item->appointment->recurrence_end);
03553             free(item->appointment);
03554         }
03555         SAFE_FREE(item->ascii_type);
03556         SAFE_FREE_STR(item->body_charset);
03557         SAFE_FREE_STR(item->body);
03558         SAFE_FREE_STR(item->subject);
03559         SAFE_FREE_STR(item->comment);
03560         SAFE_FREE(item->create_date);
03561         SAFE_FREE_STR(item->file_as);
03562         SAFE_FREE(item->modify_date);
03563         SAFE_FREE_STR(item->outlook_version);
03564         SAFE_FREE_BIN(item->record_key);
03565         SAFE_FREE_BIN(item->predecessor_change);
03566         free(item);
03567     }
03568     DEBUG_RET();
03569 }
03570 
03571 
03578 static int pst_getBlockOffsetPointer(pst_file *pf, pst_id2_tree *i2_head, pst_subblocks *subblocks, uint32_t offset, pst_block_offset_pointer *p) {
03579     size_t size;
03580     pst_block_offset block_offset;
03581     DEBUG_ENT("pst_getBlockOffsetPointer");
03582     if (p->needfree) free(p->from);
03583     p->from     = NULL;
03584     p->to       = NULL;
03585     p->needfree = 0;
03586     if (!offset) {
03587         // no data
03588         p->from = p->to = NULL;
03589     }
03590     else if ((offset & 0xf) == (uint32_t)0xf) {
03591         // external index reference
03592         DEBUG_WARN(("Found id2 %#x value. Will follow it\n", offset));
03593         size = pst_ff_getID2block(pf, offset, i2_head, &(p->from));
03594         if (size) {
03595             p->to = p->from + size;
03596             p->needfree = 1;
03597         }
03598         else {
03599             if (p->from) {
03600                 DEBUG_WARN(("size zero but non-null pointer\n"));
03601                 free(p->from);
03602             }
03603             p->from = p->to = NULL;
03604         }
03605     }
03606     else {
03607         // internal index reference
03608         size_t subindex  = offset >> 16;
03609         size_t suboffset = offset & 0xffff;
03610         if (subindex < subblocks->subblock_count) {
03611             if (pst_getBlockOffset(subblocks->subs[subindex].buf,
03612                                    subblocks->subs[subindex].read_size,
03613                                    subblocks->subs[subindex].i_offset,
03614                                    suboffset, &block_offset)) {
03615                 p->from = subblocks->subs[subindex].buf + block_offset.from;
03616                 p->to   = subblocks->subs[subindex].buf + block_offset.to;
03617             }
03618         }
03619     }
03620     DEBUG_RET();
03621     return (p->from) ? 0 : 1;
03622 }
03623 
03624 
03626 static int pst_getBlockOffset(char *buf, size_t read_size, uint32_t i_offset, uint32_t offset, pst_block_offset *p) {
03627     uint32_t low = offset & 0xf;
03628     uint32_t of1 = offset >> 4;
03629     DEBUG_ENT("pst_getBlockOffset");
03630     if (!p || !buf || !i_offset || low || (i_offset+2+of1+sizeof(*p) > read_size)) {
03631         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));
03632         DEBUG_RET();
03633         return 0;
03634     }
03635     memcpy(&(p->from), &(buf[(i_offset+2)+of1]), sizeof(p->from));
03636     memcpy(&(p->to), &(buf[(i_offset+2)+of1+sizeof(p->from)]), sizeof(p->to));
03637     LE16_CPU(p->from);
03638     LE16_CPU(p->to);
03639     DEBUG_WARN(("get block offset finds from=%i(%#x), to=%i(%#x)\n", p->from, p->from, p->to, p->to));
03640     if (p->from > p->to) {
03641         DEBUG_WARN(("get block offset from > to\n"));
03642         DEBUG_RET();
03643         return 0;
03644     }
03645     DEBUG_RET();
03646     return 1;
03647 }
03648 
03649 
03651 pst_index_ll* pst_getID(pst_file* pf, uint64_t i_id) {
03652     pst_index_ll *ptr;
03653     DEBUG_ENT("pst_getID");
03654     if (i_id == 0) {
03655         DEBUG_RET();
03656         return NULL;
03657     }
03658 
03659     //if (i_id & 1) DEBUG_INFO(("have odd id bit %#"PRIx64"\n", i_id));
03660     //if (i_id & 2) DEBUG_INFO(("have two id bit %#"PRIx64"\n", i_id));
03661     i_id -= (i_id & 1);
03662 
03663     DEBUG_INFO(("Trying to find %#"PRIx64"\n", i_id));
03664     ptr = pf->i_head;
03665     while (ptr && (ptr->i_id != i_id)) {
03666         ptr = ptr->next;
03667     }
03668     if (ptr) {DEBUG_INFO(("Found Value %#"PRIx64"\n", i_id));            }
03669     else     {DEBUG_INFO(("ERROR: Value %#"PRIx64" not found\n", i_id)); }
03670     DEBUG_RET();
03671     return ptr;
03672 }
03673 
03674 
03675 static pst_id2_tree *pst_getID2(pst_id2_tree *head, uint64_t id2) {
03676     DEBUG_ENT("pst_getID2");
03677     DEBUG_INFO(("looking for id2 = %#"PRIx64"\n", id2));
03678     pst_id2_tree *ptr = head;
03679     while (ptr) {
03680         if (ptr->id2 == id2) break;
03681         if (ptr->child) {
03682             pst_id2_tree *rc = pst_getID2(ptr->child, id2);
03683             if (rc) {
03684                 DEBUG_RET();
03685                 return rc;
03686             }
03687         }
03688         ptr = ptr->next;
03689     }
03690     if (ptr && ptr->id) {
03691         DEBUG_INFO(("Found value %#"PRIx64"\n", ptr->id->i_id));
03692         DEBUG_RET();
03693         return ptr;
03694     }
03695     DEBUG_INFO(("ERROR Not Found\n"));
03696     DEBUG_RET();
03697     return NULL;
03698 }
03699 
03700 
03709 static pst_desc_tree* pst_getDptr(pst_file *pf, uint64_t d_id) {
03710     pst_desc_tree *ptr = pf->d_head;
03711     DEBUG_ENT("pst_getDptr");
03712     while (ptr && (ptr->d_id != d_id)) {
03713         //DEBUG_INFO(("Looking for %#"PRIx64" at node %#"PRIx64" with parent %#"PRIx64"\n", id, ptr->d_id, ptr->parent_d_id));
03714         if (ptr->child) {
03715             ptr = ptr->child;
03716             continue;
03717         }
03718         while (!ptr->next && ptr->parent) {
03719             ptr = ptr->parent;
03720         }
03721         ptr = ptr->next;
03722     }
03723     DEBUG_RET();
03724     return ptr; // will be NULL or record we are looking for
03725 }
03726 
03727 
03728 static void pst_printDptr(pst_file *pf, pst_desc_tree *ptr) {
03729     DEBUG_ENT("pst_printDptr");
03730     while (ptr) {
03731         DEBUG_INFO(("%#"PRIx64" [%i] desc=%#"PRIx64", assoc tree=%#"PRIx64"\n", ptr->d_id, ptr->no_child,
03732                     (ptr->desc       ? ptr->desc->i_id       : (uint64_t)0),
03733                     (ptr->assoc_tree ? ptr->assoc_tree->i_id : (uint64_t)0)));
03734         if (ptr->child) {
03735             pst_printDptr(pf, ptr->child);
03736         }
03737         ptr = ptr->next;
03738     }
03739     DEBUG_RET();
03740 }
03741 
03742 
03743 static void pst_printID2ptr(pst_id2_tree *ptr) {
03744     DEBUG_ENT("pst_printID2ptr");
03745     while (ptr) {
03746         DEBUG_INFO(("%#"PRIx64" id=%#"PRIx64"\n", ptr->id2, (ptr->id ? ptr->id->i_id : (uint64_t)0)));
03747         if (ptr->child) pst_printID2ptr(ptr->child);
03748         ptr = ptr->next;
03749     }
03750     DEBUG_RET();
03751 }
03752 
03753 
03763 static size_t pst_read_block_size(pst_file *pf, int64_t offset, size_t size, char **buf) {
03764     size_t rsize;
03765     DEBUG_ENT("pst_read_block_size");
03766     DEBUG_INFO(("Reading block from %#"PRIx64", %x bytes\n", offset, size));
03767 
03768     if (*buf) {
03769         DEBUG_INFO(("Freeing old memory\n"));
03770         free(*buf);
03771     }
03772     *buf = (char*) pst_malloc(size);
03773 
03774     rsize = pst_getAtPos(pf, offset, *buf, size);
03775     if (rsize != size) {
03776         DEBUG_WARN(("Didn't read all the data. fread returned less [%i instead of %i]\n", rsize, size));
03777         if (feof(pf->fp)) {
03778             DEBUG_WARN(("We tried to read past the end of the file at [offset %#"PRIx64", size %#x]\n", offset, size));
03779         } else if (ferror(pf->fp)) {
03780             DEBUG_WARN(("Error is set on file stream.\n"));
03781         } else {
03782             DEBUG_WARN(("I can't tell why it failed\n"));
03783         }
03784     }
03785 
03786     DEBUG_RET();
03787     return rsize;
03788 }
03789 
03790 
03801 static int pst_decrypt(uint64_t i_id, char *buf, size_t size, unsigned char type) {
03802     size_t x = 0;
03803     unsigned char y;
03804     DEBUG_ENT("pst_decrypt");
03805     if (!buf) {
03806         DEBUG_RET();
03807         return -1;
03808     }
03809 
03810     if (type == PST_COMP_ENCRYPT) {
03811         x = 0;
03812         while (x < size) {
03813             y = (unsigned char)(buf[x]);
03814             buf[x] = (char)comp_enc[y]; // transpose from encrypt array
03815             x++;
03816         }
03817 
03818     } else if (type == PST_ENCRYPT) {
03819         // The following code was based on the information at
03820         // http://www.passcape.com/outlook_passwords.htm
03821         uint16_t salt = (uint16_t) (((i_id & 0x00000000ffff0000) >> 16) ^ (i_id & 0x000000000000ffff));
03822         x = 0;
03823         while (x < size) {
03824             uint8_t losalt = (salt & 0x00ff);
03825             uint8_t hisalt = (salt & 0xff00) >> 8;
03826             y = (unsigned char)buf[x];
03827             y += losalt;
03828             y = comp_high1[y];
03829             y += hisalt;
03830             y = comp_high2[y];
03831             y -= hisalt;
03832             y = comp_enc[y];
03833             y -= losalt;
03834             buf[x] = (char)y;
03835             x++;
03836             salt++;
03837         }
03838 
03839     } else {
03840         DEBUG_WARN(("Unknown encryption: %i. Cannot decrypt\n", type));
03841         DEBUG_RET();
03842         return -1;
03843     }
03844     DEBUG_RET();
03845     return 0;
03846 }
03847 
03848 
03849 static uint64_t pst_getIntAt(pst_file *pf, char *buf) {
03850     uint64_t buf64;
03851     uint32_t buf32;
03852     if (pf->do_read64) {
03853         memcpy(&buf64, buf, sizeof(buf64));
03854         LE64_CPU(buf64);
03855         return buf64;
03856     }
03857     else {
03858         memcpy(&buf32, buf, sizeof(buf32));
03859         LE32_CPU(buf32);
03860         return buf32;
03861     }
03862 }
03863 
03864 
03865 static uint64_t pst_getIntAtPos(pst_file *pf, int64_t pos ) {
03866     uint64_t buf64;
03867     uint32_t buf32;
03868     if (pf->do_read64) {
03869         (void)pst_getAtPos(pf, pos, &buf64, sizeof(buf64));
03870         LE64_CPU(buf64);
03871         return buf64;
03872     }
03873     else {
03874         (void)pst_getAtPos(pf, pos, &buf32, sizeof(buf32));
03875         LE32_CPU(buf32);
03876         return buf32;
03877     }
03878 }
03879 
03889 static size_t pst_getAtPos(pst_file *pf, int64_t pos, void* buf, size_t size) {
03890     size_t rc;
03891     DEBUG_ENT("pst_getAtPos");
03892 //  pst_block_recorder **t = &pf->block_head;
03893 //  pst_block_recorder *p = pf->block_head;
03894 //  while (p && ((p->offset+p->size) <= pos)) {
03895 //      t = &p->next;
03896 //      p = p->next;
03897 //  }
03898 //  if (p && (p->offset <= pos) && (pos < (p->offset+p->size))) {
03899 //      // bump the count
03900 //      p->readcount++;
03901 //  } else {
03902 //      // add a new block
03903 //      pst_block_recorder *tail = *t;
03904 //      p = (pst_block_recorder*)pst_malloc(sizeof(*p));
03905 //      *t = p;
03906 //      p->next      = tail;
03907 //      p->offset    = pos;
03908 //      p->size      = size;
03909 //      p->readcount = 1;
03910 //  }
03911 //  DEBUG_INFO(("pst file old offset %#"PRIx64" old size %#x read count %i offset %#"PRIx64" size %#x\n",
03912 //              p->offset, p->size, p->readcount, pos, size));
03913 
03914     if (fseeko(pf->fp, pos, SEEK_SET) == -1) {
03915         DEBUG_RET();
03916         return 0;
03917     }
03918     rc = fread(buf, (size_t)1, size, pf->fp);
03919     DEBUG_RET();
03920     return rc;
03921 }
03922 
03923 
03932 size_t pst_ff_getIDblock_dec(pst_file *pf, uint64_t i_id, char **buf) {
03933     size_t r;
03934     int noenc = (int)(i_id & 2);   // disable encryption
03935     DEBUG_ENT("pst_ff_getIDblock_dec");
03936     DEBUG_INFO(("for id %#"PRIx64"\n", i_id));
03937     r = pst_ff_getIDblock(pf, i_id, buf);
03938     if ((pf->encryption) && !(noenc)) {
03939         (void)pst_decrypt(i_id, *buf, r, pf->encryption);
03940     }
03941     DEBUG_HEXDUMPC(*buf, r, 16);
03942     DEBUG_RET();
03943     return r;
03944 }
03945 
03946 
03955 static size_t pst_ff_getIDblock(pst_file *pf, uint64_t i_id, char** buf) {
03956     pst_index_ll *rec;
03957     size_t rsize;
03958     DEBUG_ENT("pst_ff_getIDblock");
03959     rec = pst_getID(pf, i_id);
03960     if (!rec) {
03961         DEBUG_INFO(("Cannot find ID %#"PRIx64"\n", i_id));
03962         DEBUG_RET();
03963         return 0;
03964     }
03965     DEBUG_INFO(("id = %#"PRIx64", record size = %#x, offset = %#x\n", i_id, rec->size, rec->offset));
03966     rsize = pst_read_block_size(pf, rec->offset, rec->size, buf);
03967     DEBUG_RET();
03968     return rsize;
03969 }
03970 
03971 
03972 static size_t pst_ff_getID2block(pst_file *pf, uint64_t id2, pst_id2_tree *id2_head, char** buf) {
03973     size_t ret;
03974     pst_id2_tree* ptr;
03975     pst_holder h = {buf, NULL, 0, 0, 0};
03976     DEBUG_ENT("pst_ff_getID2block");
03977     ptr = pst_getID2(id2_head, id2);
03978 
03979     if (!ptr) {
03980         DEBUG_WARN(("Cannot find id2 value %#"PRIx64"\n", id2));
03981         DEBUG_RET();
03982         return 0;
03983     }
03984     ret = pst_ff_getID2data(pf, ptr->id, &h);
03985     DEBUG_RET();
03986     return ret;
03987 }
03988 
03989 
03998 static size_t pst_ff_getID2data(pst_file *pf, pst_index_ll *ptr, pst_holder *h) {
03999     size_t ret;
04000     char *b = NULL;
04001     DEBUG_ENT("pst_ff_getID2data");
04002     if (!(ptr->i_id & 0x02)) {
04003         ret = pst_ff_getIDblock_dec(pf, ptr->i_id, &b);
04004         ret = pst_append_holder(h, (size_t)0, &b, ret);
04005         free(b);
04006     } else {
04007         // here we will assume it is an indirection block that points to others
04008         DEBUG_INFO(("Assuming it is a multi-block record because of it's id %#"PRIx64"\n", ptr->i_id));
04009         ret = pst_ff_compile_ID(pf, ptr->i_id, h, (size_t)0);
04010     }
04011     ret = pst_finish_cleanup_holder(h, ret);
04012     DEBUG_RET();
04013     return ret;
04014 }
04015 
04016 
04026 static size_t pst_ff_compile_ID(pst_file *pf, uint64_t i_id, pst_holder *h, size_t size) {
04027     size_t    z, a;
04028     uint16_t  count, y;
04029     char      *buf3 = NULL;
04030     char      *buf2 = NULL;
04031     char      *b_ptr;
04032     pst_block_hdr  block_hdr;
04033     pst_table3_rec table3_rec;  //for type 3 (0x0101) blocks
04034 
04035     DEBUG_ENT("pst_ff_compile_ID");
04036     a = pst_ff_getIDblock(pf, i_id, &buf3);
04037     if (!a) {
04038         if (buf3) free(buf3);
04039         DEBUG_RET();
04040         return 0;
04041     }
04042     DEBUG_HEXDUMPC(buf3, a, 16);
04043     memcpy(&block_hdr, buf3, sizeof(block_hdr));
04044     LE16_CPU(block_hdr.index_offset);
04045     LE16_CPU(block_hdr.type);
04046     LE32_CPU(block_hdr.offset);
04047     DEBUG_INFO(("block header (index_offset=%#hx, type=%#hx, offset=%#x)\n", block_hdr.index_offset, block_hdr.type, block_hdr.offset));
04048 
04049     count = block_hdr.type;
04050     b_ptr = buf3 + 8;
04051 
04052     // For indirect lookups through a table of i_ids, just recurse back into this
04053     // function, letting it concatenate all the data together, and then return the
04054     // total size of the data.
04055     if (block_hdr.index_offset == (uint16_t)0x0201) { // Indirect lookup (depth 2).
04056         for (y=0; y<count; y++) {
04057             b_ptr += pst_decode_type3(pf, &table3_rec, b_ptr);
04058             size = pst_ff_compile_ID(pf, table3_rec.id, h, size);
04059         }
04060         free(buf3);
04061         DEBUG_RET();
04062         return size;
04063     }
04064 
04065     if (block_hdr.index_offset != (uint16_t)0x0101) { //type 3
04066         DEBUG_WARN(("WARNING: not a type 0x0101 buffer, Treating as normal buffer\n"));
04067         if (pf->encryption) (void)pst_decrypt(i_id, buf3, a, pf->encryption);
04068         size = pst_append_holder(h, size, &buf3, a);
04069         free(buf3);
04070         DEBUG_RET();
04071         return size;
04072     }
04073 
04074     for (y=0; y<count; y++) {
04075         b_ptr += pst_decode_type3(pf, &table3_rec, b_ptr);
04076         z = pst_ff_getIDblock_dec(pf, table3_rec.id, &buf2);
04077         if (!z) {
04078             DEBUG_WARN(("call to getIDblock returned zero %i\n", z));
04079             if (buf2) free(buf2);
04080             free(buf3);
04081             DEBUG_RET();
04082             return z;
04083         }
04084         size = pst_append_holder(h, size, &buf2, z);
04085     }
04086 
04087     free(buf3);
04088     if (buf2) free(buf2);
04089     DEBUG_RET();
04090     return size;
04091 }
04092 
04093 
04102 static size_t pst_append_holder(pst_holder *h, size_t size, char **buf, size_t z) {
04103     char *t;
04104     DEBUG_ENT("pst_append_holder");
04105 
04106     // raw append to a buffer
04107     if (h->buf) {
04108         *(h->buf) = pst_realloc(*(h->buf), size+z+1);
04109         DEBUG_INFO(("appending read data of size %i onto main buffer from pos %i\n", z, size));
04110         memcpy(*(h->buf)+size, *buf, z);
04111 
04112     // base64 encoding to a file
04113     } else if ((h->base64 == 1) && h->fp) {
04114         //
04115         if (h->base64_extra) {
04116             // include any bytes left over from the last encoding
04117             *buf = (char*)pst_realloc(*buf, z+h->base64_extra);
04118             memmove(*buf+h->base64_extra, *buf, z);
04119             memcpy(*buf, h->base64_extra_chars, h->base64_extra);
04120             z += h->base64_extra;
04121         }
04122 
04123         // find out how many bytes will be left over after this encoding and save them
04124         h->base64_extra = z % 3;
04125         if (h->base64_extra) {
04126             z -= h->base64_extra;
04127             memcpy(h->base64_extra_chars, *buf+z, h->base64_extra);
04128         }
04129 
04130         // encode this chunk
04131         t = pst_base64_encode_multiple(*buf, z, &h->base64_line_count);
04132         if (t) {
04133             DEBUG_INFO(("writing %i bytes to file as base64 [%i]. Currently %i\n", z, strlen(t), size));
04134             (void)pst_fwrite(t, (size_t)1, strlen(t), h->fp);
04135             free(t);    // caught by valgrind
04136         }
04137 
04138     // raw append to a file
04139     } else if (h->fp) {
04140         DEBUG_INFO(("writing %i bytes to file. Currently %i\n", z, size));
04141         (void)pst_fwrite(*buf, (size_t)1, z, h->fp);
04142 
04143     // null output
04144     } else {
04145         // h-> does not specify any output
04146     }
04147     DEBUG_RET();
04148     return size+z;
04149 }
04150 
04151 
04158 static size_t pst_finish_cleanup_holder(pst_holder *h, size_t size) {
04159     char *t;
04160     DEBUG_ENT("pst_finish_cleanup_holder");
04161     if ((h->base64 == 1) && h->fp && h->base64_extra) {
04162         // need to encode any bytes left over
04163         t = pst_base64_encode_multiple(h->base64_extra_chars, h->base64_extra, &h->base64_line_count);
04164         if (t) {
04165             (void)pst_fwrite(t, (size_t)1, strlen(t), h->fp);
04166             free(t);    // caught by valgrind
04167         }
04168         size += h->base64_extra;
04169     }
04170     DEBUG_RET();
04171     return size;
04172 }
04173 
04174 
04178 int pst_stricmp(char *a, char *b) {
04179     while(*a != '\0' && *b != '\0' && toupper(*a)==toupper(*b)) {
04180         a++; b++;
04181     }
04182     if (toupper(*a) == toupper(*b))
04183         return 0;
04184     else if (toupper(*a) < toupper(*b))
04185         return -1;
04186     else
04187         return 1;
04188 }
04189 
04190 
04191 static int pst_strincmp(char *a, char *b, size_t x) {
04192     // compare upto x chars in string a and b case-insensitively
04193     // returns -1 if a < b, 0 if a==b, 1 if a > b
04194     size_t y = 0;
04195     while (*a != '\0' && *b != '\0' && y < x && toupper(*a)==toupper(*b)) {
04196         a++; b++; y++;
04197     }
04198     // if we have reached the end of either string, or a and b still match
04199     if (*a == '\0' || *b == '\0' || toupper(*a)==toupper(*b))
04200         return 0;
04201     else if (toupper(*a) < toupper(*b))
04202         return -1;
04203     else
04204         return 1;
04205 }
04206 
04207 
04208 size_t pst_fwrite(const void* ptr, size_t size, size_t nmemb, FILE *stream) {
04209     size_t r;
04210     if (ptr)
04211         r = fwrite(ptr, size, nmemb, stream);
04212     else {
04213         r = 0;
04214         DEBUG_ENT("pst_fwrite");
04215         DEBUG_WARN(("An attempt to write a NULL Pointer was made\n"));
04216         DEBUG_RET();
04217     }
04218     return r;
04219 }
04220 
04221 
04222 static char* pst_wide_to_single(char *wt, size_t size) {
04223     // returns the first byte of each wide char. the size is the number of bytes in source
04224     char *x, *y;
04225     DEBUG_ENT("pst_wide_to_single");
04226     x = pst_malloc((size/2)+1);
04227     y = x;
04228     while (size != 0 && *wt != '\0') {
04229         *y = *wt;
04230         wt+=2;
04231         size -= 2;
04232         y++;
04233     }
04234     *y = '\0';
04235     DEBUG_RET();
04236     return x;
04237 }
04238 
04239 
04240 char* pst_rfc2426_escape(char* str, char **buf, size_t* buflen) {
04241     //static char*  buf    = NULL;
04242     //static size_t buflen = 0;
04243     char *ret, *a, *b;
04244     size_t x = 0;
04245     int y, z;
04246     if (!str) return NULL;
04247     DEBUG_ENT("rfc2426_escape");
04248     // calculate space required to escape all the following characters
04249     y = pst_chr_count(str, ',')
04250       + pst_chr_count(str, '\\')
04251       + pst_chr_count(str, ';')
04252       + pst_chr_count(str, '\n');
04253     z = pst_chr_count(str, '\r');
04254     if (y == 0 && z == 0)
04255         // there isn't any extra space required
04256         ret = str;
04257     else {
04258         x = strlen(str) + y - z + 1; // don't forget room for the NUL
04259         if (x > *buflen) {
04260             *buf = (char*)pst_realloc(*buf, x);
04261             *buflen = x;
04262         }
04263         a = str;
04264         b = *buf;
04265         while (*a != '\0') {
04266             switch (*a) {
04267             case ',' :
04268             case '\\':
04269             case ';' :
04270                 *(b++) = '\\';
04271                 *b = *a;
04272                 break;
04273             case '\n':  // newlines are encoded as "\n"
04274                 *(b++) = '\\';
04275                 *b = 'n';
04276                 break;
04277             case '\r':  // skip cr
04278                 b--;
04279                 break;
04280             default:
04281                 *b=*a;
04282             }
04283             b++;
04284             a++;
04285         }
04286         *b = '\0'; // NUL-terminate the string (buf)
04287         ret = *buf;
04288     }
04289     DEBUG_RET();
04290     return ret;
04291 }
04292 
04293 
04294 static int pst_chr_count(char *str, char x) {
04295     int r = 0;
04296     while (*str) {
04297         if (*str == x) r++;
04298         str++;
04299     }
04300     return r;
04301 }
04302 
04303 
04304 char* pst_rfc2425_datetime_format(const FILETIME* ft, int buflen, char* result) {
04305     struct tm stm;
04306     DEBUG_ENT("rfc2425_datetime_format");
04307     pst_fileTimeToStructTM(ft, &stm);
04308     if (strftime(result, buflen, "%Y-%m-%dT%H:%M:%SZ", &stm)==0) {
04309         DEBUG_INFO(("Problem occured formatting date\n"));
04310     }
04311     DEBUG_RET();
04312     return result;
04313 }
04314 
04315 
04316 char* pst_rfc2445_datetime_format(const FILETIME* ft, int buflen, char* result) {
04317     struct tm stm;
04318     DEBUG_ENT("rfc2445_datetime_format");
04319     pst_fileTimeToStructTM(ft, &stm);
04320     if (strftime(result, buflen, "%Y%m%dT%H%M%SZ", &stm)==0) {
04321         DEBUG_INFO(("Problem occured formatting date\n"));
04322     }
04323     DEBUG_RET();
04324     return result;
04325 }
04326 
04327 
04328 char* pst_rfc2445_datetime_format_now(int buflen, char* result) {
04329     struct tm stm;
04330     time_t t = time(NULL);
04331     DEBUG_ENT("rfc2445_datetime_format_now");
04332     gmtime_r(&t, &stm);
04333     if (strftime(result, buflen, "%Y%m%dT%H%M%SZ", &stm)==0) {
04334         DEBUG_INFO(("Problem occured formatting date\n"));
04335     }
04336     DEBUG_RET();
04337     return result;
04338 }
04339 
04340 
04349 static const char* codepage(int cp, int buflen, char* result);
04350 static const char* codepage(int cp, int buflen, char* result) {
04351     switch (cp) {
04352         case   932 : return "iso-2022-jp";
04353         case   936 : return "gb2313";
04354         case   950 : return "big5";
04355         case  1200 : return "ucs-2le";
04356         case  1201 : return "ucs-2be";
04357         case 20127 : return "us-ascii";
04358         case 20269 : return "iso-6937";
04359         case 20865 : return "iso-8859-15";
04360         case 20866 : return "koi8-r";
04361         case 21866 : return "koi8-u";
04362         case 28591 : return "iso-8859-1";
04363         case 28592 : return "iso-8859-2";
04364         case 28595 : return "iso-8859-5";
04365         case 28596 : return "iso-8859-6";
04366         case 28597 : return "iso-8859-7";
04367         case 28598 : return "iso-8859-8";
04368         case 28599 : return "iso-8859-9";
04369         case 28600 : return "iso-8859-10";
04370         case 28601 : return "iso-8859-11";
04371         case 28602 : return "iso-8859-12";
04372         case 28603 : return "iso-8859-13";
04373         case 28604 : return "iso-8859-14";
04374         case 28605 : return "iso-8859-15";
04375         case 28606 : return "iso-8859-16";
04376         case 50220 : return "iso-2022-jp";
04377         case 50221 : return "csiso2022jp";
04378         case 51932 : return "euc-jp";
04379         case 51949 : return "euc-kr";
04380         case 65000 : return "utf-7";
04381         case 65001 : return "utf-8";
04382         default :
04383             snprintf(result, buflen, "windows-%d", cp);
04384             return result;
04385     }
04386     return NULL;
04387 }
04388 
04389 
04398 const char*    pst_default_charset(pst_item *item, int buflen, char* result) {
04399     return (item->body_charset.str)         ? item->body_charset.str :
04400            (item->message_codepage)         ? codepage(item->message_codepage, buflen, result) :
04401            (item->internet_cpid)            ? codepage(item->internet_cpid, buflen, result) :
04402            (item->pf && item->pf->charset)  ? item->pf->charset :
04403            "iso-8859-1";
04404 }
04405 
04406 
04411 void pst_rfc2231(pst_string *str) {
04412     int needs = 0;
04413     const int8_t *x = (int8_t *)str->str;
04414     while (*x) {
04415         if (*x <= 32) needs++;
04416         x++;
04417     }
04418     int n = strlen(str->str) + 2*needs + 15;
04419     char *buffer = pst_malloc(n);
04420     strcpy(buffer, "utf-8''");
04421     x = (int8_t *)str->str;
04422     const uint8_t *y = (uint8_t *)str->str;
04423     uint8_t *z = (uint8_t *)buffer;
04424     z += strlen(buffer);    // skip the utf8 prefix
04425     while (*y) {
04426         if (*x <= 32) {
04427             *(z++) = (uint8_t)'%';
04428             snprintf(z, 3, "%2x", *y);
04429             z += 2;
04430         }
04431         else {
04432             *(z++) = *y;
04433         }
04434         x++;
04435         y++;
04436     }
04437     *z = '\0';
04438     free(str->str);
04439     str->str = buffer;
04440 }
04441 
04442 
04449 void pst_rfc2047(pst_item *item, pst_string *str, int needs_quote) {
04450     int has_space = 0;
04451     int needs_coding = 0;
04452     pst_convert_utf8(item, str);
04453     const int8_t *x = (int8_t *)str->str;
04454     while (*x) {
04455         if (*x == 32) has_space = 1;
04456         if (*x < 32)  needs_coding = 1;
04457         x++;
04458     }
04459     if (needs_coding) {
04460         char *enc = pst_base64_encode_single(str->str, strlen(str->str));
04461         free(str->str);
04462         int n = strlen(enc) + 20;
04463         str->str = pst_malloc(n);
04464         snprintf(str->str, n, "=?utf-8?B?%s?=", enc);
04465         free(enc);
04466     }
04467     else if (has_space && needs_quote) {
04468         int n = strlen(str->str) + 10;
04469         char *buffer = pst_malloc(n);
04470         snprintf(buffer, n, "\"%s\"", str->str);
04471         free(str->str);
04472         str->str = buffer;
04473     }
04474 }
04475 
04476 
04482 void pst_convert_utf8_null(pst_item *item, pst_string *str) {
04483     if (!str->str) return;
04484     pst_convert_utf8(item, str);
04485 }
04486 
04487 
04493 void pst_convert_utf8(pst_item *item, pst_string *str) {
04494     DEBUG_ENT("pst_convert_utf8");
04495     char buffer[30];
04496     if (str->is_utf8) {
04497         DEBUG_WARN(("Already utf8\n"));
04498         DEBUG_RET();
04499         return;
04500     }
04501     if (!str->str) {
04502         str->str = strdup("");
04503         DEBUG_WARN(("null to empty string\n"));
04504         DEBUG_RET();
04505         return;
04506     }
04507     const char *charset = pst_default_charset(item, sizeof(buffer), buffer);
04508     DEBUG_WARN(("default charset is %s\n", charset));
04509     if (!strcasecmp("utf-8", charset)) {
04510         DEBUG_RET();
04511         return;
04512     }
04513     pst_vbuf *newer = pst_vballoc(2);
04514     size_t rc = pst_vb_8bit2utf8(newer, str->str, strlen(str->str) + 1, charset);
04515     if (rc == (size_t)-1) {
04516         free(newer->b);
04517         DEBUG_WARN(("Failed to convert %s to utf-8 - %s\n", charset, str->str));
04518     }
04519     else {
04520         free(str->str);
04521         str->str = newer->b;
04522         str->is_utf8 = 1;
04523     }
04524     free(newer);
04525     DEBUG_RET();
04526 }
04527 
04528 
04533 pst_recurrence* pst_convert_recurrence(pst_item_appointment* appt)
04534 {
04535     const int bias = 30 * 24 * 60;  // minutes in 30 days
04536     int m[4] = {3,4,4,5};
04537     pst_recurrence *r = pst_malloc(sizeof(pst_recurrence));
04538     memset(r, 0, sizeof(pst_recurrence));
04539     size_t s = appt->recurrence_data.size;
04540     size_t i = 0;
04541     char*  p = appt->recurrence_data.data;
04542     if (p) {
04543         if (i+4 <= s) { r->signature        = PST_LE_GET_UINT32(p+i);        i += 4; }
04544         if (i   <= s) { r->type             = PST_LE_GET_UINT8(p+i) - 0x0a;  i += 2; }
04545         if (i+4 <= s) { r->sub_type         = PST_LE_GET_UINT32(p+i);        i += 4; }
04546         if (r->sub_type <= 3) {
04547             int n = m[r->sub_type]; // number of parms for this sub_type
04548             int j = 0;
04549             for (j=0; j<n; j++) {
04550                 if (i+4 <= s) { *(&r->parm1 + j) = PST_LE_GET_UINT32(p+i);   i += 4; }
04551             }
04552         }
04553         if (i   <= s) { r->termination      = PST_LE_GET_UINT8(p+i) - 0x21;  i += 4; }
04554         if (i+4 <= s) { r->count            = PST_LE_GET_UINT32(p+i);        i += 4; }
04555         if (r->termination == 2) r->count = 0;
04556         switch (r->type) {
04557             case 0: // daily
04558                 if (r->sub_type == 0) {
04559                     // simple daily
04560                     r->interval = r->parm2 / (24 * 60); // was minutes between recurrences
04561                 }
04562                 else {
04563                     // daily every weekday, subset of weekly
04564                     r->interval  = 1;
04565                     r->bydaymask = r->parm4;
04566                 }
04567                 break;
04568             case 1: // weekly
04569                 r->interval  = r->parm2;
04570                 r->bydaymask = r->parm4;
04571                 break;
04572             case 2: // monthly
04573                 r->interval = r->parm2;
04574                 if (r->sub_type == 2) {
04575                     // monthly on day d
04576                     r->dayofmonth = r->parm4;
04577                 }
04578                 else {
04579                     // monthly on 2nd tuesday
04580                     r->bydaymask = r->parm4;
04581                     r->position  = r->parm5;
04582                 }
04583                 break;
04584             case 3: // yearly
04585                 r->interval    = 1;
04586                 r->monthofyear = ((r->parm1 + bias/2) / bias) + 1;
04587                 if (r->sub_type == 2) {
04588                     // yearly on day d of month m
04589                     r->dayofmonth  = r->parm4;
04590                 }
04591                 else {
04592                     // yearly on 2nd tuesday of month m
04593                     r->bydaymask = r->parm4;
04594                     r->position  = r->parm5;
04595                 }
04596                 break;
04597             default:
04598                 break;
04599         }
04600     }
04601     return r;
04602 }
04603 
04604 
04608 void pst_free_recurrence(pst_recurrence* r)
04609 {
04610     if (r) free(r);
04611 }

Generated on 22 Dec 2015 for 'LibPst' by  doxygen 1.6.1