libpst.c

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

Generated on 18 Jan 2013 for 'LibPst' by  doxygen 1.6.1