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

Generated on 6 Jul 2016 for 'LibPst' by  doxygen 1.6.1