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

libpst.c

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

Generated on Tue Jun 23 20:30:06 2009 for 'LibPst' by  doxygen 1.3.9.1