Main Page | Namespace List | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

libpst.c

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

Generated on Sun Jul 10 16:52:28 2011 for 'LibPst' by  doxygen 1.3.9.1