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

Generated on Mon Sep 13 14:51:48 2010 for 'LibPst' by  doxygen 1.3.9.1