'LibPst'
libpst.c
Go to the documentation of this file.
1 /***
2  * libpst.c
3  * Part of the LibPST project
4  * Written by David Smith
5  * dave.s@earthcorp.com
6  */
7 
8 #include "define.h"
9 #include "zlib.h"
10 
11 
12 // switch to maximal packing for our own internal structures
13 // use the same code as in libpst.h
14 #ifdef _MSC_VER
15  #pragma pack(push, 1)
16 #endif
17 #if defined(__GNUC__) || defined (__SUNPRO_C) || defined(__SUNPRO_CC)
18  #pragma pack(1)
19 #endif
20 
21 #define ASSERT(x) { if(!(x)) raise( SIGSEGV ); }
22 
23 #define INDEX_TYPE32 0x0E
24 #define INDEX_TYPE32A 0x0F // unknown, but assumed to be similar for now
25 #define INDEX_TYPE64 0x17
26 #define INDEX_TYPE64A 0x15 // http://sourceforge.net/projects/libpff/
27 #define INDEX_TYPE4K 0x24
28 #define INDEX_TYPE_OFFSET (int64_t)0x0A
29 
30 #define FILE_SIZE_POINTER32 (int64_t)0xA8
31 #define INDEX_POINTER32 (int64_t)0xC4
32 #define INDEX_BACK32 (int64_t)0xC0
33 #define SECOND_POINTER32 (int64_t)0xBC
34 #define SECOND_BACK32 (int64_t)0xB8
35 #define ENC_TYPE32 (int64_t)0x1CD
36 
37 #define FILE_SIZE_POINTER64 (int64_t)0xB8
38 #define INDEX_POINTER64 (int64_t)0xF0
39 #define INDEX_BACK64 (int64_t)0xE8
40 #define SECOND_POINTER64 (int64_t)0xE0
41 #define SECOND_BACK64 (int64_t)0xD8
42 #define ENC_TYPE64 (int64_t)0x201
43 
44 #define FILE_SIZE_POINTER ((pf->do_read64) ? FILE_SIZE_POINTER64 : FILE_SIZE_POINTER32)
45 #define INDEX_POINTER ((pf->do_read64) ? INDEX_POINTER64 : INDEX_POINTER32)
46 #define INDEX_BACK ((pf->do_read64) ? INDEX_BACK64 : INDEX_BACK32)
47 #define SECOND_POINTER ((pf->do_read64) ? SECOND_POINTER64 : SECOND_POINTER32)
48 #define SECOND_BACK ((pf->do_read64) ? SECOND_BACK64 : SECOND_BACK32)
49 #define ENC_TYPE ((pf->do_read64) ? ENC_TYPE64 : ENC_TYPE32)
50 
51 
52 #define PST_SIGNATURE 0x4E444221
53 
54 
55 typedef struct pst_block_offset {
56  uint16_t from;
57  uint16_t to;
59 
60 
61 typedef struct pst_block_offset_pointer {
62  char *from;
63  char *to;
64  int needfree;
66 
67 
68 typedef struct pst_holder {
69  char **buf;
70  FILE *fp;
71  int base64; // bool, are we encoding into base64
72  int base64_line_count; // base64 bytes emitted on the current line
73  size_t base64_extra; // count of bytes held in base64_extra_chars
74  char base64_extra_chars[2]; // up to two pending unencoded bytes
75 } pst_holder;
76 
77 
78 typedef struct pst_subblock {
79  char *buf;
80  size_t read_size;
81  size_t i_offset;
82 } pst_subblock;
83 
84 
85 typedef struct pst_subblocks {
89 
90 
91 typedef struct pst_mapi_element {
92  uint32_t mapi_id;
93  char *data;
94  uint32_t type;
95  size_t size;
96  char *extra;
98 
99 
100 typedef struct pst_mapi_object {
101  int32_t count_elements; // count of active elements
102  int32_t orig_count; // originally allocated elements
103  int32_t count_objects; // number of mapi objects in the list
107 
108 
109 typedef struct pst_desc32 {
110  uint32_t d_id;
111  uint32_t desc_id;
112  uint32_t tree_id;
113  uint32_t parent_d_id;
114 } pst_desc32;
115 
116 
117 typedef struct pst_index32 {
118  uint32_t id;
119  uint32_t offset;
120  uint16_t size;
121  int16_t u1;
122 } pst_index32;
123 
124 
126  uint32_t start;
127  uint32_t u1;
128  uint32_t offset;
129 };
130 
131 
132 typedef struct pst_desc {
133  uint64_t d_id;
134  uint64_t desc_id;
135  uint64_t tree_id;
136  uint32_t parent_d_id; // not 64 bit
137  uint32_t u1; // padding
138 } pst_desc;
139 
140 
141 typedef struct pst_index64 {
142  uint64_t id;
143  uint64_t offset;
144  uint16_t size;
145  int16_t u0;
146  int32_t u1;
147 } pst_index64;
148 
149 typedef struct pst_index {
150  uint64_t id;
151  uint64_t offset;
152  uint16_t size;
153  uint16_t inflated_size;
154  int16_t u0;
155  int32_t u1;
156 } pst_index;
157 
158 
160  uint64_t start;
161  uint64_t u1;
162  uint64_t offset;
163 };
164 
165 
166 typedef struct pst_block_header {
167  uint16_t type;
168  uint16_t count;
170 
171 
172 typedef struct pst_id2_assoc32 {
173  uint32_t id2;
174  uint32_t id;
175  uint32_t child_id;
177 
178 
179 typedef struct pst_id2_assoc {
180  uint32_t id2; // only 32 bit here
181  uint16_t unknown1;
182  uint16_t unknown2;
183  uint64_t id;
184  uint64_t child_id;
185 } pst_id2_assoc;
186 
187 
188 typedef struct pst_table3_rec32 {
189  uint32_t id;
190 } pst_table3_rec32; //for type 3 (0x0101) blocks
191 
192 
193 typedef struct pst_table3_rec {
194  uint64_t id;
195 } pst_table3_rec; //for type 3 (0x0101) blocks
196 
197 
198 typedef struct pst_block_hdr {
199  uint16_t index_offset;
200  uint16_t type;
201  uint32_t offset;
202 } pst_block_hdr;
203 
204 
209 static unsigned char comp_enc [] = {
210  0x47, 0xf1, 0xb4, 0xe6, 0x0b, 0x6a, 0x72, 0x48, 0x85, 0x4e, 0x9e, 0xeb, 0xe2, 0xf8, 0x94, 0x53,
211  0xe0, 0xbb, 0xa0, 0x02, 0xe8, 0x5a, 0x09, 0xab, 0xdb, 0xe3, 0xba, 0xc6, 0x7c, 0xc3, 0x10, 0xdd,
212  0x39, 0x05, 0x96, 0x30, 0xf5, 0x37, 0x60, 0x82, 0x8c, 0xc9, 0x13, 0x4a, 0x6b, 0x1d, 0xf3, 0xfb,
213  0x8f, 0x26, 0x97, 0xca, 0x91, 0x17, 0x01, 0xc4, 0x32, 0x2d, 0x6e, 0x31, 0x95, 0xff, 0xd9, 0x23,
214  0xd1, 0x00, 0x5e, 0x79, 0xdc, 0x44, 0x3b, 0x1a, 0x28, 0xc5, 0x61, 0x57, 0x20, 0x90, 0x3d, 0x83,
215  0xb9, 0x43, 0xbe, 0x67, 0xd2, 0x46, 0x42, 0x76, 0xc0, 0x6d, 0x5b, 0x7e, 0xb2, 0x0f, 0x16, 0x29,
216  0x3c, 0xa9, 0x03, 0x54, 0x0d, 0xda, 0x5d, 0xdf, 0xf6, 0xb7, 0xc7, 0x62, 0xcd, 0x8d, 0x06, 0xd3,
217  0x69, 0x5c, 0x86, 0xd6, 0x14, 0xf7, 0xa5, 0x66, 0x75, 0xac, 0xb1, 0xe9, 0x45, 0x21, 0x70, 0x0c,
218  0x87, 0x9f, 0x74, 0xa4, 0x22, 0x4c, 0x6f, 0xbf, 0x1f, 0x56, 0xaa, 0x2e, 0xb3, 0x78, 0x33, 0x50,
219  0xb0, 0xa3, 0x92, 0xbc, 0xcf, 0x19, 0x1c, 0xa7, 0x63, 0xcb, 0x1e, 0x4d, 0x3e, 0x4b, 0x1b, 0x9b,
220  0x4f, 0xe7, 0xf0, 0xee, 0xad, 0x3a, 0xb5, 0x59, 0x04, 0xea, 0x40, 0x55, 0x25, 0x51, 0xe5, 0x7a,
221  0x89, 0x38, 0x68, 0x52, 0x7b, 0xfc, 0x27, 0xae, 0xd7, 0xbd, 0xfa, 0x07, 0xf4, 0xcc, 0x8e, 0x5f,
222  0xef, 0x35, 0x9c, 0x84, 0x2b, 0x15, 0xd5, 0x77, 0x34, 0x49, 0xb6, 0x12, 0x0a, 0x7f, 0x71, 0x88,
223  0xfd, 0x9d, 0x18, 0x41, 0x7d, 0x93, 0xd8, 0x58, 0x2c, 0xce, 0xfe, 0x24, 0xaf, 0xde, 0xb8, 0x36,
224  0xc8, 0xa1, 0x80, 0xa6, 0x99, 0x98, 0xa8, 0x2f, 0x0e, 0x81, 0x65, 0x73, 0xe4, 0xc2, 0xa2, 0x8a,
225  0xd4, 0xe1, 0x11, 0xd0, 0x08, 0x8b, 0x2a, 0xf2, 0xed, 0x9a, 0x64, 0x3f, 0xc1, 0x6c, 0xf9, 0xec
226 };
227 
230 static unsigned char comp_high1 [] = {
231  0x41, 0x36, 0x13, 0x62, 0xa8, 0x21, 0x6e, 0xbb, 0xf4, 0x16, 0xcc, 0x04, 0x7f, 0x64, 0xe8, 0x5d,
232  0x1e, 0xf2, 0xcb, 0x2a, 0x74, 0xc5, 0x5e, 0x35, 0xd2, 0x95, 0x47, 0x9e, 0x96, 0x2d, 0x9a, 0x88,
233  0x4c, 0x7d, 0x84, 0x3f, 0xdb, 0xac, 0x31, 0xb6, 0x48, 0x5f, 0xf6, 0xc4, 0xd8, 0x39, 0x8b, 0xe7,
234  0x23, 0x3b, 0x38, 0x8e, 0xc8, 0xc1, 0xdf, 0x25, 0xb1, 0x20, 0xa5, 0x46, 0x60, 0x4e, 0x9c, 0xfb,
235  0xaa, 0xd3, 0x56, 0x51, 0x45, 0x7c, 0x55, 0x00, 0x07, 0xc9, 0x2b, 0x9d, 0x85, 0x9b, 0x09, 0xa0,
236  0x8f, 0xad, 0xb3, 0x0f, 0x63, 0xab, 0x89, 0x4b, 0xd7, 0xa7, 0x15, 0x5a, 0x71, 0x66, 0x42, 0xbf,
237  0x26, 0x4a, 0x6b, 0x98, 0xfa, 0xea, 0x77, 0x53, 0xb2, 0x70, 0x05, 0x2c, 0xfd, 0x59, 0x3a, 0x86,
238  0x7e, 0xce, 0x06, 0xeb, 0x82, 0x78, 0x57, 0xc7, 0x8d, 0x43, 0xaf, 0xb4, 0x1c, 0xd4, 0x5b, 0xcd,
239  0xe2, 0xe9, 0x27, 0x4f, 0xc3, 0x08, 0x72, 0x80, 0xcf, 0xb0, 0xef, 0xf5, 0x28, 0x6d, 0xbe, 0x30,
240  0x4d, 0x34, 0x92, 0xd5, 0x0e, 0x3c, 0x22, 0x32, 0xe5, 0xe4, 0xf9, 0x9f, 0xc2, 0xd1, 0x0a, 0x81,
241  0x12, 0xe1, 0xee, 0x91, 0x83, 0x76, 0xe3, 0x97, 0xe6, 0x61, 0x8a, 0x17, 0x79, 0xa4, 0xb7, 0xdc,
242  0x90, 0x7a, 0x5c, 0x8c, 0x02, 0xa6, 0xca, 0x69, 0xde, 0x50, 0x1a, 0x11, 0x93, 0xb9, 0x52, 0x87,
243  0x58, 0xfc, 0xed, 0x1d, 0x37, 0x49, 0x1b, 0x6a, 0xe0, 0x29, 0x33, 0x99, 0xbd, 0x6c, 0xd9, 0x94,
244  0xf3, 0x40, 0x54, 0x6f, 0xf0, 0xc6, 0x73, 0xb8, 0xd6, 0x3e, 0x65, 0x18, 0x44, 0x1f, 0xdd, 0x67,
245  0x10, 0xf1, 0x0c, 0x19, 0xec, 0xae, 0x03, 0xa1, 0x14, 0x7b, 0xa9, 0x0b, 0xff, 0xf8, 0xa3, 0xc0,
246  0xa2, 0x01, 0xf7, 0x2e, 0xbc, 0x24, 0x68, 0x75, 0x0d, 0xfe, 0xba, 0x2f, 0xb5, 0xd0, 0xda, 0x3d
247 };
248 
251 static unsigned char comp_high2 [] = {
252  0x14, 0x53, 0x0f, 0x56, 0xb3, 0xc8, 0x7a, 0x9c, 0xeb, 0x65, 0x48, 0x17, 0x16, 0x15, 0x9f, 0x02,
253  0xcc, 0x54, 0x7c, 0x83, 0x00, 0x0d, 0x0c, 0x0b, 0xa2, 0x62, 0xa8, 0x76, 0xdb, 0xd9, 0xed, 0xc7,
254  0xc5, 0xa4, 0xdc, 0xac, 0x85, 0x74, 0xd6, 0xd0, 0xa7, 0x9b, 0xae, 0x9a, 0x96, 0x71, 0x66, 0xc3,
255  0x63, 0x99, 0xb8, 0xdd, 0x73, 0x92, 0x8e, 0x84, 0x7d, 0xa5, 0x5e, 0xd1, 0x5d, 0x93, 0xb1, 0x57,
256  0x51, 0x50, 0x80, 0x89, 0x52, 0x94, 0x4f, 0x4e, 0x0a, 0x6b, 0xbc, 0x8d, 0x7f, 0x6e, 0x47, 0x46,
257  0x41, 0x40, 0x44, 0x01, 0x11, 0xcb, 0x03, 0x3f, 0xf7, 0xf4, 0xe1, 0xa9, 0x8f, 0x3c, 0x3a, 0xf9,
258  0xfb, 0xf0, 0x19, 0x30, 0x82, 0x09, 0x2e, 0xc9, 0x9d, 0xa0, 0x86, 0x49, 0xee, 0x6f, 0x4d, 0x6d,
259  0xc4, 0x2d, 0x81, 0x34, 0x25, 0x87, 0x1b, 0x88, 0xaa, 0xfc, 0x06, 0xa1, 0x12, 0x38, 0xfd, 0x4c,
260  0x42, 0x72, 0x64, 0x13, 0x37, 0x24, 0x6a, 0x75, 0x77, 0x43, 0xff, 0xe6, 0xb4, 0x4b, 0x36, 0x5c,
261  0xe4, 0xd8, 0x35, 0x3d, 0x45, 0xb9, 0x2c, 0xec, 0xb7, 0x31, 0x2b, 0x29, 0x07, 0x68, 0xa3, 0x0e,
262  0x69, 0x7b, 0x18, 0x9e, 0x21, 0x39, 0xbe, 0x28, 0x1a, 0x5b, 0x78, 0xf5, 0x23, 0xca, 0x2a, 0xb0,
263  0xaf, 0x3e, 0xfe, 0x04, 0x8c, 0xe7, 0xe5, 0x98, 0x32, 0x95, 0xd3, 0xf6, 0x4a, 0xe8, 0xa6, 0xea,
264  0xe9, 0xf3, 0xd5, 0x2f, 0x70, 0x20, 0xf2, 0x1f, 0x05, 0x67, 0xad, 0x55, 0x10, 0xce, 0xcd, 0xe3,
265  0x27, 0x3b, 0xda, 0xba, 0xd7, 0xc2, 0x26, 0xd4, 0x91, 0x1d, 0xd2, 0x1c, 0x22, 0x33, 0xf8, 0xfa,
266  0xf1, 0x5a, 0xef, 0xcf, 0x90, 0xb6, 0x8b, 0xb5, 0xbd, 0xc0, 0xbf, 0x08, 0x97, 0x1e, 0x6c, 0xe2,
267  0x61, 0xe0, 0xc6, 0xc1, 0x59, 0xab, 0xbb, 0x58, 0xde, 0x5f, 0xdf, 0x60, 0x79, 0x7e, 0xb2, 0x8a
268 };
269 
270 static size_t pst_append_holder(pst_holder *h, size_t size, char **buf, size_t z);
271 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);
272 static pst_id2_tree* pst_build_id2(pst_file *pf, pst_index_ll* list);
273 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);
274 static int pst_chr_count(char *str, char x);
275 static size_t pst_ff_compile_ID(pst_file *pf, uint64_t i_id, pst_holder *h, size_t size);
276 static size_t pst_ff_getIDblock(pst_file *pf, uint64_t i_id, char** buf);
277 static size_t pst_ff_getID2block(pst_file *pf, uint64_t id2, pst_id2_tree *id2_head, char** buf);
278 static size_t pst_ff_getID2data(pst_file *pf, pst_index_ll *ptr, pst_holder *h);
279 static size_t pst_finish_cleanup_holder(pst_holder *h, size_t size);
280 static void pst_free_attach(pst_item_attach *attach);
281 static void pst_free_desc (pst_desc_tree *head);
282 static void pst_free_id2(pst_id2_tree * head);
283 static void pst_free_list(pst_mapi_object *list);
284 static void pst_free_xattrib(pst_x_attrib_ll *x);
285 static size_t pst_getAtPos(pst_file *pf, int64_t pos, void* buf, size_t size);
286 static int pst_getBlockOffsetPointer(pst_file *pf, pst_id2_tree *i2_head, pst_subblocks *subblocks, uint32_t offset, pst_block_offset_pointer *p);
287 static int pst_getBlockOffset(char *buf, size_t read_size, uint32_t i_offset, uint32_t offset, pst_block_offset *p);
288 static pst_id2_tree* pst_getID2(pst_id2_tree * ptr, uint64_t id);
289 static pst_desc_tree* pst_getDptr(pst_file *pf, uint64_t d_id);
290 static uint64_t pst_getIntAt(pst_file *pf, char *buf);
291 static uint64_t pst_getIntAtPos(pst_file *pf, int64_t pos);
292 static pst_mapi_object* pst_parse_block(pst_file *pf, uint64_t block_id, pst_id2_tree *i2_head);
293 static void pst_printDptr(pst_file *pf, pst_desc_tree *ptr);
294 static void pst_printID2ptr(pst_id2_tree *ptr);
295 static int pst_process(uint64_t block_id, pst_mapi_object *list, pst_item *item, pst_item_attach *attach);
296 static size_t pst_read_block_size(pst_file *pf, int64_t offset, size_t size, size_t inflated_size, char **buf);
297 static size_t pst_read_raw_block_size(pst_file *pf, int64_t offset, size_t size, char **buf);
298 static int pst_decrypt(uint64_t i_id, char *buf, size_t size, unsigned char type);
299 static int pst_strincmp(char *a, char *b, size_t x);
300 static char* pst_wide_to_single(char *wt, size_t size);
301 
302 
303 static char *pst_getcwd(void) {
304  char *cwd;
305 #ifdef HAVE_GET_CURRENT_DIR_NAME
306  cwd = get_current_dir_name();
307 #else
308  cwd = pst_malloc(PATH_MAX+1);
309  getcwd(cwd, PATH_MAX+1);
310 #endif
311  return cwd;
312 }
313 
314 
315 int pst_open(pst_file *pf, const char *name, const char *charset) {
316  int32_t sig;
317 
319 
320  DEBUG_ENT("pst_open");
321 
322  if (!pf) {
323  WARN (("cannot be passed a NULL pst_file\n"));
324  DEBUG_RET();
325  return -1;
326  }
327  memset(pf, 0, sizeof(*pf));
328  pf->charset = charset;
329 
330  if ((pf->fp = fopen(name, "rb")) == NULL) {
331  perror("Error opening PST file");
332  DEBUG_RET();
333  return -1;
334  }
335 
336  // Check pst file magic
337  if (pst_getAtPos(pf, 0, &sig, sizeof(sig)) != sizeof(sig)) {
338  (void)fclose(pf->fp);
339  DEBUG_WARN(("cannot read signature from PST file. Closing with error\n"));
340  DEBUG_RET();
341  return -1;
342  }
343  LE32_CPU(sig);
344  DEBUG_INFO(("sig = %X\n", sig));
345  if (sig != (int32_t)PST_SIGNATURE) {
346  (void)fclose(pf->fp);
347  DEBUG_WARN(("not a PST file that I know. Closing with error\n"));
348  DEBUG_RET();
349  return -1;
350  }
351 
352  // read index type
353  (void)pst_getAtPos(pf, INDEX_TYPE_OFFSET, &(pf->ind_type), sizeof(pf->ind_type));
354  DEBUG_INFO(("index_type = %i\n", pf->ind_type));
355  switch (pf->ind_type) {
356  case INDEX_TYPE32 :
357  case INDEX_TYPE32A :
358  pf->do_read64 = 0;
359  break;
360  case INDEX_TYPE64 :
361  case INDEX_TYPE64A :
362  pf->do_read64 = 1;
363  break;
364  case INDEX_TYPE4K :
365  pf->do_read64 = 2;
366  break;
367  default:
368  (void)fclose(pf->fp);
369  DEBUG_WARN(("unknown .pst format, possibly newer than Outlook 2003 PST file?\n"));
370  DEBUG_RET();
371  return -1;
372  }
373 
374  // read encryption setting
375  (void)pst_getAtPos(pf, ENC_TYPE, &(pf->encryption), sizeof(pf->encryption));
376  DEBUG_INFO(("encrypt = %i\n", pf->encryption));
377 
381  DEBUG_INFO(("Pointer2 is %#"PRIx64", back pointer2 is %#"PRIx64"\n", pf->index2, pf->index2_back));
382 
385  DEBUG_INFO(("Pointer1 is %#"PRIx64", back pointer2 is %#"PRIx64"\n", pf->index1, pf->index1_back));
386 
387  DEBUG_RET();
388 
389  pf->cwd = pst_getcwd();
390  pf->fname = strdup(name);
391  return 0;
392 }
393 
394 
396  char *cwd;
397  cwd = pst_getcwd();
398  if (cwd == NULL) return -1;
399  if (chdir(pf->cwd)) goto err;
400  if (!freopen(pf->fname, "rb", pf->fp)) goto err;
401  if (chdir(cwd)) goto err;
402  free(cwd);
403  return 0;
404 err:
405  free(cwd);
406  return -1;
407 }
408 
409 
410 int pst_close(pst_file *pf) {
411  DEBUG_ENT("pst_close");
412  if (!pf) {
413  DEBUG_RET();
414  return 0;
415  }
416  if (!pf->fp) {
417  DEBUG_RET();
418  return 0;
419  }
420  if (fclose(pf->fp)) {
421  DEBUG_WARN(("fclose returned non-zero value\n"));
422  }
423  // free the paths
424  free(pf->cwd);
425  free(pf->fname);
426  // we must free the id array and the desc tree
427  free(pf->i_table);
428  pst_free_desc(pf->d_head);
430  DEBUG_RET();
431  return 0;
432 }
433 
434 
442 static void add_descriptor_to_list(pst_desc_tree *node, pst_desc_tree **head, pst_desc_tree **tail);
444 {
445  DEBUG_ENT("add_descriptor_to_list");
446  //DEBUG_INFO(("Added node %#"PRIx64" parent %#"PRIx64" real parent %#"PRIx64" prev %#"PRIx64" next %#"PRIx64"\n",
447  // node->id, node->parent_d_id,
448  // (node->parent ? node->parent->id : (uint64_t)0),
449  // (node->prev ? node->prev->id : (uint64_t)0),
450  // (node->next ? node->next->id : (uint64_t)0)));
451  if (*tail) (*tail)->next = node;
452  if (!(*head)) *head = node;
453  node->prev = *tail;
454  node->next = NULL;
455  *tail = node;
456  DEBUG_RET();
457 }
458 
459 
466 static void record_descriptor(pst_file *pf, pst_desc_tree *node);
467 static void record_descriptor(pst_file *pf, pst_desc_tree *node)
468 {
469  DEBUG_ENT("record_descriptor");
470  // finish node initialization
471  node->parent = NULL;
472  node->child = NULL;
473  node->child_tail = NULL;
474  node->no_child = 0;
475 
476  // find any orphan children of this node, and collect them
477  pst_desc_tree *n = pf->d_head;
478  while (n) {
479  if (n->parent_d_id == node->d_id) {
480  // found a child of this node
481  DEBUG_INFO(("Found orphan child %#"PRIx64" of parent %#"PRIx64"\n", n->d_id, node->d_id));
482  pst_desc_tree *nn = n->next;
483  pst_desc_tree *pp = n->prev;
484  node->no_child++;
485  n->parent = node;
486  add_descriptor_to_list(n, &node->child, &node->child_tail);
487  if (pp) pp->next = nn; else pf->d_head = nn;
488  if (nn) nn->prev = pp; else pf->d_tail = pp;
489  n = nn;
490  }
491  else {
492  n = n->next;
493  }
494  }
495 
496  // now hook this node into the global tree
497  if (node->parent_d_id == 0) {
498  // add top level node to the descriptor tree
499  //DEBUG_INFO(("Null parent\n"));
500  add_descriptor_to_list(node, &pf->d_head, &pf->d_tail);
501  }
502  else if (node->parent_d_id == node->d_id) {
503  // add top level node to the descriptor tree
504  DEBUG_INFO(("%#"PRIx64" is its own parent. What is this world coming to?\n", node->d_id));
505  add_descriptor_to_list(node, &pf->d_head, &pf->d_tail);
506  } else {
507  //DEBUG_INFO(("Searching for parent %#"PRIx64" of %#"PRIx64"\n", node->parent_d_id, node->d_id));
508  pst_desc_tree *parent = pst_getDptr(pf, node->parent_d_id);
509  if (parent) {
510  //DEBUG_INFO(("Found parent %#"PRIx64"\n", node->parent_d_id));
511  parent->no_child++;
512  node->parent = parent;
513  add_descriptor_to_list(node, &parent->child, &parent->child_tail);
514  }
515  else {
516  DEBUG_INFO(("No parent %#"PRIx64", have an orphan child %#"PRIx64"\n", node->parent_d_id, node->d_id));
517  add_descriptor_to_list(node, &pf->d_head, &pf->d_tail);
518  }
519  }
520  DEBUG_RET();
521 }
522 
523 
531 static pst_id2_tree* deep_copy(pst_id2_tree *head);
533 {
534  if (!head) return NULL;
536  me->id2 = head->id2;
537  me->id = head->id;
538  me->child = deep_copy(head->child);
539  me->next = deep_copy(head->next);
540  return me;
541 }
542 
543 
545  pst_desc_tree *topnode;
546  uint32_t topid;
547  DEBUG_ENT("pst_getTopOfFolders");
548  if (!root || !root->message_store) {
549  DEBUG_INFO(("There isn't a top of folder record here.\n"));
550  DEBUG_RET();
551  return NULL;
552  }
554  // this is the OST way
555  // ASSUMPTION: Top Of Folders record in PST files is *always* descid 0x2142
556  topid = 0x2142;
557  } else {
558  topid = root->message_store->top_of_personal_folder->id;
559  }
560  DEBUG_INFO(("looking for top of folder descriptor %#"PRIx32"\n", topid));
561  topnode = pst_getDptr(pf, (uint64_t)topid);
562  if (!topnode) {
563  // add dummy top record to pickup orphan children
564  topnode = (pst_desc_tree*) pst_malloc(sizeof(pst_desc_tree));
565  topnode->d_id = topid;
566  topnode->parent_d_id = 0;
567  topnode->assoc_tree = NULL;
568  topnode->desc = NULL;
569  record_descriptor(pf, topnode); // add to the global tree
570  }
571  DEBUG_RET();
572  return topnode;
573 }
574 
575 
577  pst_index_ll *ptr;
578  pst_binary rc;
579  pst_holder h = {&rc.data, NULL, 0, 0, 0};
580  rc.size = 0;
581  rc.data = NULL;
582  DEBUG_ENT("pst_attach_to_mem");
583  if ((!attach->data.data) && (attach->i_id != (uint64_t)-1)) {
584  ptr = pst_getID(pf, attach->i_id);
585  if (ptr) {
586  rc.size = pst_ff_getID2data(pf, ptr, &h);
587  } else {
588  DEBUG_WARN(("Couldn't find ID pointer. Cannot handle attachment\n"));
589  }
590  } else {
591  rc = attach->data;
592  attach->data.data = NULL; // prevent pst_free_item() from trying to free this
593  attach->data.size = 0; // since we have given that buffer to the caller
594  }
595  DEBUG_RET();
596  return rc;
597 }
598 
599 
600 size_t pst_attach_to_file(pst_file *pf, pst_item_attach *attach, FILE* fp) {
601  pst_index_ll *ptr;
602  pst_holder h = {NULL, fp, 0, 0, 0};
603  size_t size = 0;
604  DEBUG_ENT("pst_attach_to_file");
605  if ((!attach->data.data) && (attach->i_id != (uint64_t)-1)) {
606  ptr = pst_getID(pf, attach->i_id);
607  if (ptr) {
608  size = pst_ff_getID2data(pf, ptr, &h);
609  } else {
610  DEBUG_WARN(("Couldn't find ID pointer. Cannot save attachment to file\n"));
611  }
612  } else {
613  size = attach->data.size;
614  if (attach->data.data && size) {
615  // save the attachment to the file
616  (void)pst_fwrite(attach->data.data, (size_t)1, size, fp);
617  }
618  }
619  DEBUG_RET();
620  return size;
621 }
622 
623 
624 size_t pst_attach_to_file_base64(pst_file *pf, pst_item_attach *attach, FILE* fp) {
625  pst_index_ll *ptr;
626  pst_holder h = {NULL, fp, 1, 0, 0};
627  size_t size = 0;
628  DEBUG_ENT("pst_attach_to_file_base64");
629  if ((!attach->data.data) && (attach->i_id != (uint64_t)-1)) {
630  ptr = pst_getID(pf, attach->i_id);
631  if (ptr) {
632  size = pst_ff_getID2data(pf, ptr, &h);
633  } else {
634  DEBUG_WARN(("Couldn't find ID pointer. Cannot save attachment to Base64\n"));
635  }
636  } else {
637  size = attach->data.size;
638  if (attach->data.data && size) {
639  // encode the attachment to the file
640  char *c = pst_base64_encode(attach->data.data, size);
641  if (c) {
642  (void)pst_fwrite(c, (size_t)1, strlen(c), fp);
643  free(c); // caught by valgrind
644  }
645  }
646  }
647  DEBUG_RET();
648  return size;
649 }
650 
651 
653  int x;
654  DEBUG_ENT("pst_load_index");
655  if (!pf) {
656  DEBUG_WARN(("Cannot load index for a NULL pst_file\n"));
657  DEBUG_RET();
658  return -1;
659  }
660 
661  x = pst_build_id_ptr(pf, pf->index1, 0, pf->index1_back, 0, UINT64_MAX);
662  DEBUG_INFO(("build id ptr returns %i\n", x));
663 
664  x = pst_build_desc_ptr(pf, pf->index2, 0, pf->index2_back, (uint64_t)0x21, UINT64_MAX);
665  DEBUG_INFO(("build desc ptr returns %i\n", x));
666 
667  pst_printDptr(pf, pf->d_head);
668 
669  DEBUG_RET();
670  return 0;
671 }
672 
673 
675  pst_desc_tree* r = NULL;
676  DEBUG_ENT("pst_getNextDptr");
677  if (d) {
678  if ((r = d->child) == NULL) {
679  while (!d->next && d->parent) d = d->parent;
680  r = d->next;
681  }
682  }
683  DEBUG_RET();
684  return r;
685 }
686 
687 
688 typedef struct pst_x_attrib {
689  uint32_t extended;
690  uint16_t type;
691  uint16_t map;
692 } pst_x_attrib;
693 
694 
699  // for PST files this will load up d_id 0x61 and check it's "assoc_tree" attribute.
700  pst_desc_tree *p;
701  pst_mapi_object *list;
702  pst_id2_tree *id2_head = NULL;
703  char *buffer=NULL, *headerbuffer=NULL;
704  size_t bsize=0, hsize=0, bptr=0;
705  pst_x_attrib xattrib;
706  int32_t tint, x;
707  pst_x_attrib_ll *ptr, *p_head=NULL;
708 
709  DEBUG_ENT("pst_loadExtendedAttributes");
710  p = pst_getDptr(pf, (uint64_t)0x61);
711  if (!p) {
712  DEBUG_WARN(("Cannot find d_id 0x61 for loading the Extended Attributes\n"));
713  DEBUG_RET();
714  return 0;
715  }
716 
717  if (!p->desc) {
718  DEBUG_WARN(("descriptor is NULL for d_id 0x61. Cannot load Extended Attributes\n"));
719  DEBUG_RET();
720  return 0;
721  }
722 
723  if (p->assoc_tree) {
724  id2_head = pst_build_id2(pf, p->assoc_tree);
725  pst_printID2ptr(id2_head);
726  } else {
727  DEBUG_WARN(("Have not been able to fetch any id2 values for d_id 0x61. Brace yourself!\n"));
728  }
729 
730  list = pst_parse_block(pf, p->desc->i_id, id2_head);
731  if (!list) {
732  DEBUG_WARN(("Cannot process desc block for item 0x61. Not loading extended Attributes\n"));
733  pst_free_id2(id2_head);
734  DEBUG_RET();
735  return 0;
736  }
737 
738  DEBUG_INFO(("look through d_id 0x61 list of mapi objects\n"));
739  for (x=0; x < list->count_elements; x++) {
740  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));
741  if (list->elements[x]->data) {
742  DEBUG_HEXDUMPC(list->elements[x]->data, list->elements[x]->size, 0x10);
743  }
744  if (list->elements[x]->mapi_id == (uint32_t)0x0003) {
745  buffer = list->elements[x]->data;
746  bsize = list->elements[x]->size;
747  } else if (list->elements[x]->mapi_id == (uint32_t)0x0004) {
748  headerbuffer = list->elements[x]->data;
749  hsize = list->elements[x]->size;
750  } else {
751  // leave them null
752  }
753  }
754 
755  if (!buffer) {
756  pst_free_list(list);
757  DEBUG_WARN(("No extended attributes buffer found. Not processing\n"));
758  DEBUG_RET();
759  return 0;
760  }
761 
762  while (bptr < bsize) {
763  int err = 0;
764  xattrib.extended= PST_LE_GET_UINT32(buffer+bptr), bptr += 4;
765  xattrib.type = PST_LE_GET_UINT16(buffer+bptr), bptr += 2;
766  xattrib.map = PST_LE_GET_UINT16(buffer+bptr), bptr += 2;
767  ptr = (pst_x_attrib_ll*) pst_malloc(sizeof(*ptr));
768  memset(ptr, 0, sizeof(*ptr));
769  ptr->map = xattrib.map+0x8000;
770  ptr->next = NULL;
771  DEBUG_INFO(("xattrib: ext = %#"PRIx32", type = %#"PRIx16", map = %#"PRIx16"\n",
772  xattrib.extended, xattrib.type, xattrib.map));
773  if (xattrib.type & 0x0001) { // if the Bit 1 is set
774  // pointer to Unicode field in buffer
775  if (xattrib.extended < hsize) {
776  char *wt;
777  // copy the size of the header. It is 32 bit int
778  memcpy(&tint, &(headerbuffer[xattrib.extended]), sizeof(tint));
779  LE32_CPU(tint);
780  wt = (char*) pst_malloc((size_t)(tint+2)); // plus 2 for a uni-code zero
781  memset(wt, 0, (size_t)(tint+2));
782  memcpy(wt, &(headerbuffer[xattrib.extended+sizeof(tint)]), (size_t)tint);
783  ptr->data = pst_wide_to_single(wt, (size_t)tint);
784  free(wt);
785  DEBUG_INFO(("Mapped attribute %#"PRIx32" to %s\n", ptr->map, ptr->data));
786  } else {
787  DEBUG_INFO(("Cannot read outside of buffer [%i !< %i]\n", xattrib.extended, hsize));
788  err = 1;
789  }
790  ptr->mytype = PST_MAP_HEADER;
791  } else {
792  // contains the attribute code to map to.
793  ptr->data = (uint32_t*)pst_malloc(sizeof(uint32_t));
794  memset(ptr->data, 0, sizeof(uint32_t));
795  *((uint32_t*)ptr->data) = xattrib.extended;
796  ptr->mytype = PST_MAP_ATTRIB;
797  DEBUG_INFO(("Mapped attribute %#"PRIx32" to %#"PRIx32"\n", ptr->map, *((uint32_t*)ptr->data)));
798  }
799 
800  if (!err) {
801  // add it to the list
802  pst_x_attrib_ll *p_sh = p_head;
803  pst_x_attrib_ll *p_sh2 = NULL;
804  while (p_sh && (ptr->map > p_sh->map)) {
805  p_sh2 = p_sh;
806  p_sh = p_sh->next;
807  }
808  if (!p_sh2) {
809  // needs to go before first item
810  ptr->next = p_head;
811  p_head = ptr;
812  } else {
813  // it will go after p_sh2
814  ptr->next = p_sh2->next;
815  p_sh2->next = ptr;
816  }
817  } else {
818  free(ptr);
819  }
820  }
821  pst_free_id2(id2_head);
822  pst_free_list(list);
823  pf->x_head = p_head;
824  DEBUG_RET();
825  return 1;
826 }
827 
828 
829 #define ITEM_COUNT_OFFSET32 0x1f0 // count byte
830 #define MAX_COUNT_OFFSET32 0x1f1
831 #define ENTRY_SIZE_OFFSET32 0x1f2
832 #define LEVEL_INDICATOR_OFFSET32 0x1f3 // node or leaf
833 #define BACKLINK_OFFSET32 0x1f8 // backlink u1 value
834 
835 #define ITEM_COUNT_OFFSET64 0x1e8 // count byte
836 #define MAX_COUNT_OFFSET64 0x1e9
837 #define ENTRY_SIZE_OFFSET64 0x1ea // node or leaf
838 #define LEVEL_INDICATOR_OFFSET64 0x1eb // node or leaf
839 #define BACKLINK_OFFSET64 0x1f8 // backlink u1 value
840 
841 #define ITEM_COUNT_OFFSET4K 0xfd8
842 #define MAX_COUNT_OFFSET4K 0xfda
843 #define ENTRY_SIZE_OFFSET4K 0xfdc
844 #define LEVEL_INDICATOR_OFFSET4K 0xfdd
845 #define BACKLINK_OFFSET4K 0xff0
846 
847 #define BLOCK_SIZE (size_t)((pf->do_read64 == 2) ? 4096 : 512) // index blocks
848 #define DESC_BLOCK_SIZE (size_t)((pf->do_read64 == 2) ? 4096 : 512) // descriptor blocks
849 #define ITEM_COUNT_OFFSET (size_t)((pf->do_read64) ? (pf->do_read64 == 2 ? ITEM_COUNT_OFFSET4K : ITEM_COUNT_OFFSET64) : ITEM_COUNT_OFFSET32)
850 #define LEVEL_INDICATOR_OFFSET (size_t)((pf->do_read64) ? (pf->do_read64 == 2 ? LEVEL_INDICATOR_OFFSET4K : LEVEL_INDICATOR_OFFSET64) : LEVEL_INDICATOR_OFFSET32)
851 #define BACKLINK_OFFSET (size_t)((pf->do_read64) ? (pf->do_read64 == 2 ? BACKLINK_OFFSET4K : BACKLINK_OFFSET64) : BACKLINK_OFFSET32)
852 #define ENTRY_SIZE_OFFSET (size_t)((pf->do_read64) ? (pf->do_read64 == 2 ? ENTRY_SIZE_OFFSET4K : ENTRY_SIZE_OFFSET64) : ENTRY_SIZE_OFFSET32)
853 #define MAX_COUNT_OFFSET (size_t)((pf->do_read64) ? (pf->do_read64 == 2 ? MAX_COUNT_OFFSET4K : MAX_COUNT_OFFSET64) : MAX_COUNT_OFFSET32)
854 
855 #define read_twobyte(BUF, OFF) (int32_t) ((((unsigned)BUF[OFF + 1] & 0xFF)) << 8) | ((unsigned)BUF[OFF] & 0xFF);
856 
857 static size_t pst_decode_desc(pst_file *pf, pst_desc *desc, char *buf);
858 static size_t pst_decode_desc(pst_file *pf, pst_desc *desc, char *buf) {
859  size_t r;
860  if (pf->do_read64) {
861  DEBUG_INFO(("Decoding desc64\n"));
862  DEBUG_HEXDUMPC(buf, sizeof(pst_desc), 0x10);
863  memcpy(desc, buf, sizeof(pst_desc));
864  LE64_CPU(desc->d_id);
865  LE64_CPU(desc->desc_id);
866  LE64_CPU(desc->tree_id);
867  LE32_CPU(desc->parent_d_id);
868  LE32_CPU(desc->u1);
869  r = sizeof(pst_desc);
870  }
871  else {
872  pst_desc32 d32;
873  DEBUG_INFO(("Decoding desc32\n"));
874  DEBUG_HEXDUMPC(buf, sizeof(pst_desc32), 0x10);
875  memcpy(&d32, buf, sizeof(pst_desc32));
876  LE32_CPU(d32.d_id);
877  LE32_CPU(d32.desc_id);
878  LE32_CPU(d32.tree_id);
879  LE32_CPU(d32.parent_d_id);
880  desc->d_id = d32.d_id;
881  desc->desc_id = d32.desc_id;
882  desc->tree_id = d32.tree_id;
883  desc->parent_d_id = d32.parent_d_id;
884  desc->u1 = 0;
885  r = sizeof(pst_desc32);
886  }
887  return r;
888 }
889 
890 
891 static size_t pst_decode_table(pst_file *pf, struct pst_table_ptr_struct *table, char *buf);
892 static size_t pst_decode_table(pst_file *pf, struct pst_table_ptr_struct *table, char *buf) {
893  size_t r;
894  if (pf->do_read64) {
895  DEBUG_INFO(("Decoding table64\n"));
896  DEBUG_HEXDUMPC(buf, sizeof(struct pst_table_ptr_struct), 0x10);
897  memcpy(table, buf, sizeof(struct pst_table_ptr_struct));
898  LE64_CPU(table->start);
899  LE64_CPU(table->u1);
900  LE64_CPU(table->offset);
901  r =sizeof(struct pst_table_ptr_struct);
902  }
903  else {
904  struct pst_table_ptr_struct32 t32;
905  DEBUG_INFO(("Decoding table32\n"));
906  DEBUG_HEXDUMPC(buf, sizeof( struct pst_table_ptr_struct32), 0x10);
907  memcpy(&t32, buf, sizeof(struct pst_table_ptr_struct32));
908  LE32_CPU(t32.start);
909  LE32_CPU(t32.u1);
910  LE32_CPU(t32.offset);
911  table->start = t32.start;
912  table->u1 = t32.u1;
913  table->offset = t32.offset;
914  r = sizeof(struct pst_table_ptr_struct32);
915  }
916  return r;
917 }
918 
919 
920 static size_t pst_decode_index(pst_file *pf, pst_index *index, char *buf);
921 static size_t pst_decode_index(pst_file *pf, pst_index *index, char *buf) {
922  size_t r;
923  if (pf->do_read64 == 2) {
924  DEBUG_INFO(("Decoding index4k\n"));
925  DEBUG_HEXDUMPC(buf, sizeof(pst_index), 0x10);
926  memcpy(index, buf, sizeof(pst_index));
927  LE64_CPU(index->id);
928  LE64_CPU(index->offset);
929  LE16_CPU(index->size);
930  LE16_CPU(index->inflated_size);
931  LE16_CPU(index->u0);
932  LE32_CPU(index->u1);
933  r = sizeof(pst_index);
934  } else if (pf->do_read64 == 1) {
935  pst_index64 index64;
936  DEBUG_INFO(("Decoding index64\n"));
937  DEBUG_HEXDUMPC(buf, sizeof(pst_index64), 0x10);
938  memcpy(&index64, buf, sizeof(pst_index64));
939  LE64_CPU(index64.id);
940  LE64_CPU(index64.offset);
941  LE16_CPU(index64.size);
942  LE16_CPU(index64.u0);
943  LE32_CPU(index64.u1);
944  index->id = index64.id;
945  index->offset = index64.offset;
946  index->size = index64.size;
947  index->inflated_size = index64.size;
948  index->u0 = index64.u0;
949  index->u1 = index64.u1;
950  r = sizeof(pst_index64);
951  } else {
952  pst_index32 index32;
953  DEBUG_INFO(("Decoding index32\n"));
954  DEBUG_HEXDUMPC(buf, sizeof(pst_index32), 0x10);
955  memcpy(&index32, buf, sizeof(pst_index32));
956  LE32_CPU(index32.id);
957  LE32_CPU(index32.offset);
958  LE16_CPU(index32.size);
959  LE16_CPU(index32.u1);
960  index->id = index32.id;
961  index->offset = index32.offset;
962  index->size = index32.size;
963  index->inflated_size = index32.size;
964  index->u0 = 0;
965  index->u1 = index32.u1;
966  r = sizeof(pst_index32);
967  }
968  return r;
969 }
970 
971 
972 static size_t pst_decode_assoc(pst_file *pf, pst_id2_assoc *assoc, char *buf);
973 static size_t pst_decode_assoc(pst_file *pf, pst_id2_assoc *assoc, char *buf) {
974  size_t r;
975  if (pf->do_read64) {
976  DEBUG_INFO(("Decoding assoc64\n"));
977  DEBUG_HEXDUMPC(buf, sizeof(pst_id2_assoc), 0x10);
978  memcpy(assoc, buf, sizeof(pst_id2_assoc));
979  LE32_CPU(assoc->id2);
980  LE64_CPU(assoc->id);
981  LE64_CPU(assoc->child_id);
982  r = sizeof(pst_id2_assoc);
983  } else {
984  pst_id2_assoc32 assoc32;
985  DEBUG_INFO(("Decoding assoc32\n"));
986  DEBUG_HEXDUMPC(buf, sizeof(pst_id2_assoc32), 0x10);
987  memcpy(&assoc32, buf, sizeof(pst_id2_assoc32));
988  LE32_CPU(assoc32.id2);
989  LE32_CPU(assoc32.id);
990  LE32_CPU(assoc32.child_id);
991  assoc->id2 = assoc32.id2;
992  assoc->id = assoc32.id;
993  assoc->child_id = assoc32.child_id;
994  r = sizeof(pst_id2_assoc32);
995  }
996  return r;
997 }
998 
999 
1000 static size_t pst_decode_type3(pst_file *pf, pst_table3_rec *table3_rec, char *buf);
1001 static size_t pst_decode_type3(pst_file *pf, pst_table3_rec *table3_rec, char *buf) {
1002  size_t r;
1003  DEBUG_ENT("pst_decode_type3");
1004  if (pf->do_read64) {
1005  DEBUG_INFO(("Decoding table3 64\n"));
1006  DEBUG_HEXDUMPC(buf, sizeof(pst_table3_rec), 0x10);
1007  memcpy(table3_rec, buf, sizeof(pst_table3_rec));
1008  LE64_CPU(table3_rec->id);
1009  r = sizeof(pst_table3_rec);
1010  } else {
1011  pst_table3_rec32 table3_rec32;
1012  DEBUG_INFO(("Decoding table3 32\n"));
1013  DEBUG_HEXDUMPC(buf, sizeof(pst_table3_rec32), 0x10);
1014  memcpy(&table3_rec32, buf, sizeof(pst_table3_rec32));
1015  LE32_CPU(table3_rec32.id);
1016  table3_rec->id = table3_rec32.id;
1017  r = sizeof(pst_table3_rec32);
1018  }
1019  DEBUG_RET();
1020  return r;
1021 }
1022 
1023 
1029 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) {
1030  struct pst_table_ptr_struct table, table2;
1031  pst_index_ll *i_ptr=NULL;
1032  pst_index index;
1033  int32_t x, item_count, count_max;
1034  uint64_t old = start_val;
1035  char *buf = NULL, *bptr;
1036 
1037  DEBUG_ENT("pst_build_id_ptr");
1038  DEBUG_INFO(("offset %#"PRIx64" depth %i linku1 %#"PRIx64" start %#"PRIx64" end %#"PRIx64"\n", offset, depth, linku1, start_val, end_val));
1039  if (end_val <= start_val) {
1040  DEBUG_WARN(("The end value is BEFORE the start value. This function will quit. Soz. [start:%#"PRIx64", end:%#"PRIx64"]\n", start_val, end_val));
1041  DEBUG_RET();
1042  return -1;
1043  }
1044  DEBUG_INFO(("Reading index block\n"));
1046  DEBUG_WARN(("Failed to read %i bytes\n", BLOCK_SIZE));
1047  if (buf) free(buf);
1048  DEBUG_RET();
1049  return -1;
1050  }
1051  bptr = buf;
1052  DEBUG_HEXDUMPC(buf, BLOCK_SIZE, 0x10);
1053  if (pf->do_read64 == 2) {
1054  item_count = read_twobyte(buf, ITEM_COUNT_OFFSET);
1055  count_max = read_twobyte(buf, MAX_COUNT_OFFSET);
1056  } else {
1057  item_count = (int32_t)(unsigned)(buf[ITEM_COUNT_OFFSET]);
1058  count_max = (int32_t)(unsigned)(buf[MAX_COUNT_OFFSET]);
1059  }
1060  if (item_count > count_max) {
1061  DEBUG_WARN(("Item count %i too large, max is %i\n", item_count, count_max));
1062  if (buf) free(buf);
1063  DEBUG_RET();
1064  return -1;
1065  }
1066  index.id = pst_getIntAt(pf, buf+BACKLINK_OFFSET);
1067  if (index.id != linku1) {
1068  DEBUG_WARN(("Backlink %#"PRIx64" in this node does not match required %#"PRIx64"\n", index.id, linku1));
1069  if (buf) free(buf);
1070  DEBUG_RET();
1071  return -1;
1072  }
1073  int entry_size = (int32_t)(unsigned)(buf[ENTRY_SIZE_OFFSET]);
1074  DEBUG_INFO(("count %#"PRIx64" max %#"PRIx64" size %#"PRIx64"\n", item_count, count_max, entry_size));
1075  if (buf[LEVEL_INDICATOR_OFFSET] == '\0') {
1076  // this node contains leaf pointers
1077  x = 0;
1078  while (x < item_count) {
1079  pst_decode_index(pf, &index, bptr);
1080  bptr += entry_size;
1081  x++;
1082  if (index.id == 0) break;
1083  DEBUG_INFO(("[%i]%i Item [id = %#"PRIx64", offset = %#"PRIx64", u1 = %#x, size = %i(%#x)]\n",
1084  depth, x, index.id, index.offset, index.u1, index.size, index.size));
1085  // if (index.id & 0x02) DEBUG_INFO(("two-bit set!!\n"));
1086  if ((index.id >= end_val) || (index.id < old)) {
1087  DEBUG_WARN(("This item isn't right. Must be corruption, or I got it wrong!\n"));
1088  if (buf) free(buf);
1089  DEBUG_RET();
1090  return -1;
1091  }
1092  old = index.id;
1093  if (pf->i_count == pf->i_capacity) {
1094  pf->i_capacity += (pf->i_capacity >> 1) + 16; // arbitrary growth rate
1095  pf->i_table = pst_realloc(pf->i_table, pf->i_capacity * sizeof(pst_index_ll));
1096  }
1097  i_ptr = &pf->i_table[pf->i_count++];
1098  i_ptr->i_id = index.id;
1099  i_ptr->offset = index.offset;
1100  i_ptr->u1 = index.u1;
1101  i_ptr->size = index.size;
1102  i_ptr->inflated_size = index.inflated_size;
1103  }
1104  } else {
1105  // this node contains node pointers
1106  x = 0;
1107  while (x < item_count) {
1108  pst_decode_table(pf, &table, bptr);
1109  bptr += entry_size;
1110  x++;
1111  if (table.start == 0) break;
1112  if (x < item_count) {
1113  (void)pst_decode_table(pf, &table2, bptr);
1114  }
1115  else {
1116  table2.start = end_val;
1117  }
1118  DEBUG_INFO(("[%i] %i Index Table [start id = %#"PRIx64", u1 = %#"PRIx64", offset = %#"PRIx64", end id = %#"PRIx64"]\n",
1119  depth, x, table.start, table.u1, table.offset, table2.start));
1120  if ((table.start >= end_val) || (table.start < old)) {
1121  DEBUG_WARN(("This table isn't right. Must be corruption, or I got it wrong!\n"));
1122  if (buf) free(buf);
1123  DEBUG_RET();
1124  return -1;
1125  }
1126  old = table.start;
1127  (void)pst_build_id_ptr(pf, table.offset, depth+1, table.u1, table.start, table2.start);
1128  }
1129  }
1130  if (buf) free (buf);
1131  DEBUG_RET();
1132  return 0;
1133 }
1134 
1135 
1140 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) {
1141  struct pst_table_ptr_struct table, table2;
1142  pst_desc desc_rec;
1143  int32_t item_count, count_max;
1144  uint64_t old = start_val;
1145  int x;
1146  char *buf = NULL, *bptr;
1147 
1148  DEBUG_ENT("pst_build_desc_ptr");
1149  DEBUG_INFO(("offset %#"PRIx64" depth %i linku1 %#"PRIx64" start %#"PRIx64" end %#"PRIx64"\n", offset, depth, linku1, start_val, end_val));
1150  if (end_val <= start_val) {
1151  DEBUG_WARN(("The end value is BEFORE the start value. This function will quit. Soz. [start:%#"PRIx64", end:%#"PRIx64"]\n", start_val, end_val));
1152  DEBUG_RET();
1153  return -1;
1154  }
1155  DEBUG_INFO(("Reading desc block\n"));
1157  DEBUG_WARN(("Failed to read %i bytes\n", DESC_BLOCK_SIZE));
1158  if (buf) free(buf);
1159  DEBUG_RET();
1160  return -1;
1161  }
1162  bptr = buf;
1163  if (pf->do_read64 == 2) {
1164  item_count = read_twobyte(buf, ITEM_COUNT_OFFSET);
1165  count_max = read_twobyte(buf, MAX_COUNT_OFFSET);
1166  } else {
1167  item_count = (int32_t)(unsigned)(buf[ITEM_COUNT_OFFSET]);
1168  count_max = (int32_t)(unsigned)(buf[MAX_COUNT_OFFSET]);
1169  }
1170  desc_rec.d_id = pst_getIntAt(pf, buf+BACKLINK_OFFSET);
1171  if (desc_rec.d_id != linku1) {
1172  DEBUG_WARN(("Backlink %#"PRIx64" in this node does not match required %#"PRIx64"\n", desc_rec.d_id, linku1));
1173  if (buf) free(buf);
1174  DEBUG_RET();
1175  return -1;
1176  }
1177  int32_t entry_size = (int32_t)(unsigned)(buf[ENTRY_SIZE_OFFSET]);
1178  if (buf[LEVEL_INDICATOR_OFFSET] == '\0') {
1179  // this node contains leaf pointers
1180  DEBUG_HEXDUMPC(buf, DESC_BLOCK_SIZE, entry_size);
1181  if (item_count > count_max) {
1182  DEBUG_WARN(("Item count %i too large, max is %i\n", item_count, count_max));
1183  if (buf) free(buf);
1184  DEBUG_RET();
1185  return -1;
1186  }
1187  for (x=0; x<item_count; x++) {
1188  pst_decode_desc(pf, &desc_rec, bptr);
1189  bptr += entry_size;
1190  DEBUG_INFO(("[%i] Item(%#x) = [d_id = %#"PRIx64", desc_id = %#"PRIx64", tree_id = %#"PRIx64", parent_d_id = %#x]\n",
1191  depth, x, desc_rec.d_id, desc_rec.desc_id, desc_rec.tree_id, desc_rec.parent_d_id));
1192  if ((desc_rec.d_id >= end_val) || (desc_rec.d_id < old)) {
1193  DEBUG_WARN(("This item isn't right. Must be corruption, or I got it wrong!\n"));
1194  DEBUG_HEXDUMPC(buf, DESC_BLOCK_SIZE, 16);
1195  if (buf) free(buf);
1196  DEBUG_RET();
1197  return -1;
1198  }
1199  old = desc_rec.d_id;
1200  DEBUG_INFO(("New Record %#"PRIx64" with parent %#x\n", desc_rec.d_id, desc_rec.parent_d_id));
1201  {
1202  pst_desc_tree *d_ptr = (pst_desc_tree*) pst_malloc(sizeof(pst_desc_tree));
1203  d_ptr->d_id = desc_rec.d_id;
1204  d_ptr->parent_d_id = desc_rec.parent_d_id;
1205  d_ptr->assoc_tree = pst_getID(pf, desc_rec.tree_id);
1206  d_ptr->desc = pst_getID(pf, desc_rec.desc_id);
1207  record_descriptor(pf, d_ptr); // add to the global tree
1208  }
1209  }
1210  } else {
1211  // this node contains node pointers
1212  DEBUG_HEXDUMPC(buf, DESC_BLOCK_SIZE, entry_size);
1213  if (item_count > count_max) {
1214  DEBUG_WARN(("Item count %i too large, max is %i\n", item_count, count_max));
1215  if (buf) free(buf);
1216  DEBUG_RET();
1217  return -1;
1218  }
1219  for (x=0; x<item_count; x++) {
1220  pst_decode_table(pf, &table, bptr);
1221  bptr += entry_size;
1222  if (table.start == 0) break;
1223  if (x < (item_count-1)) {
1224  (void)pst_decode_table(pf, &table2, bptr);
1225  }
1226  else {
1227  table2.start = end_val;
1228  }
1229  DEBUG_INFO(("[%i] %i Descriptor Table [start id = %#"PRIx64", u1 = %#"PRIx64", offset = %#"PRIx64", end id = %#"PRIx64"]\n",
1230  depth, x, table.start, table.u1, table.offset, table2.start));
1231  if ((table.start >= end_val) || (table.start < old)) {
1232  DEBUG_WARN(("This table isn't right. Must be corruption, or I got it wrong!\n"));
1233  if (buf) free(buf);
1234  DEBUG_RET();
1235  return -1;
1236  }
1237  old = table.start;
1238  (void)pst_build_desc_ptr(pf, table.offset, depth+1, table.u1, table.start, table2.start);
1239  }
1240  }
1241  if (buf) free(buf);
1242  DEBUG_RET();
1243  return 0;
1244 }
1245 
1246 
1250  pst_mapi_object * list;
1251  pst_id2_tree *id2_head = m_head;
1252  pst_id2_tree *id2_ptr = NULL;
1253  pst_item *item = NULL;
1254  pst_item_attach *attach = NULL;
1255  int32_t x;
1256  DEBUG_ENT("pst_parse_item");
1257  if (!d_ptr) {
1258  DEBUG_WARN(("you cannot pass me a NULL! I don't want it!\n"));
1259  DEBUG_RET();
1260  return NULL;
1261  }
1262 
1263  if (!d_ptr->desc) {
1264  DEBUG_WARN(("why is d_ptr->desc == NULL? I don't want to do anything else with this record\n"));
1265  DEBUG_RET();
1266  return NULL;
1267  }
1268 
1269  if (d_ptr->assoc_tree) {
1270  if (m_head) {
1271  DEBUG_WARN(("supplied master head, but have a list that is building a new id2_head\n"));
1272  m_head = NULL;
1273  }
1274  id2_head = pst_build_id2(pf, d_ptr->assoc_tree);
1275  }
1276  pst_printID2ptr(id2_head);
1277 
1278  list = pst_parse_block(pf, d_ptr->desc->i_id, id2_head);
1279  if (!list) {
1280  DEBUG_WARN(("pst_parse_block() returned an error for d_ptr->desc->i_id [%#"PRIx64"]\n", d_ptr->desc->i_id));
1281  if (!m_head) pst_free_id2(id2_head);
1282  DEBUG_RET();
1283  return NULL;
1284  }
1285 
1286  item = (pst_item*) pst_malloc(sizeof(pst_item));
1287  memset(item, 0, sizeof(pst_item));
1288  item->pf = pf;
1289 
1290  if (pst_process(d_ptr->desc->i_id, list, item, NULL)) {
1291  DEBUG_WARN(("pst_process() returned non-zero value. That is an error\n"));
1292  pst_freeItem(item);
1293  pst_free_list(list);
1294  if (!m_head) pst_free_id2(id2_head);
1295  DEBUG_RET();
1296  return NULL;
1297  }
1298  pst_free_list(list);
1299 
1300  if ((id2_ptr = pst_getID2(id2_head, (uint64_t)0x692))) {
1301  // DSN/MDN reports?
1302  DEBUG_INFO(("DSN/MDN processing\n"));
1303  list = pst_parse_block(pf, id2_ptr->id->i_id, id2_ptr->child);
1304  if (list) {
1305  for (x=0; x < list->count_objects; x++) {
1306  attach = (pst_item_attach*) pst_malloc(sizeof(pst_item_attach));
1307  memset(attach, 0, sizeof(pst_item_attach));
1308  attach->next = item->attach;
1309  item->attach = attach;
1310  }
1311  if (pst_process(id2_ptr->id->i_id, list, item, item->attach)) {
1312  DEBUG_WARN(("ERROR pst_process() failed with DSN/MDN attachments\n"));
1313  pst_freeItem(item);
1314  pst_free_list(list);
1315  if (!m_head) pst_free_id2(id2_head);
1316  DEBUG_RET();
1317  return NULL;
1318  }
1319  pst_free_list(list);
1320  } else {
1321  DEBUG_WARN(("ERROR error processing main DSN/MDN record\n"));
1322  // if (!m_head) pst_free_id2(id2_head);
1323  // DEBUG_RET();
1324  // return item;
1325  }
1326  }
1327 
1328  if ((id2_ptr = pst_getID2(id2_head, (uint64_t)0x671))) {
1329  DEBUG_INFO(("ATTACHMENT processing attachment\n"));
1330  list = pst_parse_block(pf, id2_ptr->id->i_id, id2_ptr->child);
1331  if (!list) {
1332  if (item->flags & PST_FLAG_HAS_ATTACHMENT) {
1333  // Only report an error if we expected to see an attachment table and didn't.
1334  DEBUG_WARN(("ERROR error processing main attachment record\n"));
1335  }
1336  if (!m_head) pst_free_id2(id2_head);
1337  DEBUG_RET();
1338  return item;
1339  }
1340  for (x=0; x < list->count_objects; x++) {
1341  attach = (pst_item_attach*) pst_malloc(sizeof(pst_item_attach));
1342  memset(attach, 0, sizeof(pst_item_attach));
1343  attach->next = item->attach;
1344  item->attach = attach;
1345  }
1346  if (pst_process(id2_ptr->id->i_id, list, item, item->attach)) {
1347  DEBUG_WARN(("ERROR pst_process() failed with attachments\n"));
1348  pst_freeItem(item);
1349  pst_free_list(list);
1350  if (!m_head) pst_free_id2(id2_head);
1351  DEBUG_RET();
1352  return NULL;
1353  }
1354  pst_free_list(list);
1355 
1356  // now we will have initial information of each attachment stored in item->attach...
1357  // we must now read the secondary record for each based on the id2_val associated with
1358  // each attachment
1359  for (attach = item->attach; attach; attach = attach->next) {
1360  DEBUG_WARN(("initial attachment id2 %#"PRIx64"\n", attach->id2_val));
1361  if ((id2_ptr = pst_getID2(id2_head, attach->id2_val))) {
1362  DEBUG_WARN(("initial attachment id2 found id %#"PRIx64"\n", id2_ptr->id->i_id));
1363  // id2_ptr is a record describing the attachment
1364  // we pass NULL instead of id2_head cause we don't want it to
1365  // load all the extra stuff here.
1366  list = pst_parse_block(pf, id2_ptr->id->i_id, NULL);
1367  if (!list) {
1368  DEBUG_WARN(("ERROR error processing an attachment record\n"));
1369  continue;
1370  }
1371  if (list->count_objects > 1) {
1372  DEBUG_WARN(("ERROR probably fatal, list count array will overrun attach structure.\n"));
1373  }
1374  // reprocess the same attachment list against new data
1375  // this might update attach->id2_val
1376  if (pst_process(id2_ptr->id->i_id, list, item, attach)) {
1377  DEBUG_WARN(("ERROR pst_process() failed with an attachment\n"));
1378  pst_free_list(list);
1379  continue;
1380  }
1381  pst_free_list(list);
1382  // As per 2.4.6.2 in the spec, the attachment data is stored as a child of the
1383  // attachment object, so we pass in id2_ptr as the head to search from.
1384  id2_ptr = pst_getID2(id2_ptr->child, attach->id2_val);
1385  if (id2_ptr) {
1386  DEBUG_WARN(("second pass attachment updating id2 %#"PRIx64" found i_id %#"PRIx64"\n", attach->id2_val, id2_ptr->id->i_id));
1387  // i_id has been updated to the datablock containing the attachment data
1388  attach->i_id = id2_ptr->id->i_id;
1389  attach->id2_head = deep_copy(id2_ptr->child);
1390  } else {
1391  DEBUG_WARN(("have not located the correct value for the attachment [%#"PRIx64"]\n", attach->id2_val));
1392  }
1393  } else {
1394  DEBUG_WARN(("ERROR cannot locate id2 value %#"PRIx64"\n", attach->id2_val));
1395  attach->id2_val = 0; // suppress this missing attachment
1396  }
1397  }
1398  }
1399 
1400  if (!m_head) pst_free_id2(id2_head);
1401  DEBUG_RET();
1402  return item;
1403 }
1404 
1405 
1406 static void freeall(pst_subblocks *subs, pst_block_offset_pointer *p1,
1420  size_t i;
1421  for (i=0; i<subs->subblock_count; i++) {
1422  if (subs->subs[i].buf) free(subs->subs[i].buf);
1423  }
1424  free(subs->subs);
1425  if (p1->needfree) free(p1->from);
1426  if (p2->needfree) free(p2->from);
1427  if (p3->needfree) free(p3->from);
1428  if (p4->needfree) free(p4->from);
1429  if (p5->needfree) free(p5->from);
1430  if (p6->needfree) free(p6->from);
1431  if (p7->needfree) free(p7->from);
1432 }
1433 
1434 
1440 static pst_mapi_object* pst_parse_block(pst_file *pf, uint64_t block_id, pst_id2_tree *i2_head) {
1441  pst_mapi_object *mo_head = NULL;
1442  char *buf = NULL;
1443  size_t read_size = 0;
1444  pst_subblocks subblocks;
1445  pst_mapi_object *mo_ptr = NULL;
1446  pst_block_offset_pointer block_offset1;
1447  pst_block_offset_pointer block_offset2;
1448  pst_block_offset_pointer block_offset3;
1449  pst_block_offset_pointer block_offset4;
1450  pst_block_offset_pointer block_offset5;
1451  pst_block_offset_pointer block_offset6;
1452  pst_block_offset_pointer block_offset7;
1453  int32_t x;
1454  int32_t num_mapi_objects;
1455  int32_t count_mapi_objects;
1456  int32_t num_mapi_elements;
1457  int32_t count_mapi_elements;
1458  int block_type;
1459  uint32_t rec_size = 0;
1460  char* list_start;
1461  char* fr_ptr;
1462  char* to_ptr;
1463  char* ind2_end = NULL;
1464  char* ind2_ptr = NULL;
1465  char* ind2_block_start = NULL;
1466  size_t ind2_max_block_size = pf->do_read64 ? 0x1FF0 : 0x1FF4;
1467  pst_x_attrib_ll *mapptr;
1468  pst_block_hdr block_hdr;
1469  pst_table3_rec table3_rec; //for type 3 (0x0101) blocks
1470 
1471  struct {
1472  unsigned char seven_c;
1473  unsigned char item_count;
1474  uint16_t u1;
1475  uint16_t u2;
1476  uint16_t u3;
1477  uint16_t rec_size;
1478  uint32_t b_five_offset;
1479  uint32_t ind2_offset;
1480  uint16_t u7;
1481  uint16_t u8;
1482  } seven_c_blk;
1483 
1484  struct _type_d_rec {
1485  uint32_t id;
1486  uint32_t u1;
1487  } * type_d_rec;
1488 
1489  struct {
1490  uint16_t type;
1491  uint16_t ref_type;
1492  uint32_t value;
1493  } table_rec; //for type 1 (0xBCEC) blocks
1494 
1495  struct {
1496  uint16_t ref_type;
1497  uint16_t type;
1498  uint16_t ind2_off;
1499  uint8_t size;
1500  uint8_t slot;
1501  } table2_rec; //for type 2 (0x7CEC) blocks
1502 
1503  DEBUG_ENT("pst_parse_block");
1504  if ((read_size = pst_ff_getIDblock_dec(pf, block_id, &buf)) == 0) {
1505  DEBUG_WARN(("Error reading block id %#"PRIx64"\n", block_id));
1506  if (buf) free (buf);
1507  DEBUG_RET();
1508  return NULL;
1509  }
1510 
1511  block_offset1.needfree = 0;
1512  block_offset2.needfree = 0;
1513  block_offset3.needfree = 0;
1514  block_offset4.needfree = 0;
1515  block_offset5.needfree = 0;
1516  block_offset6.needfree = 0;
1517  block_offset7.needfree = 0;
1518 
1519  memcpy(&block_hdr, buf, sizeof(block_hdr));
1520  LE16_CPU(block_hdr.index_offset);
1521  LE16_CPU(block_hdr.type);
1522  LE32_CPU(block_hdr.offset);
1523  DEBUG_INFO(("block header (index_offset=%#hx, type=%#hx, offset=%#hx)\n", block_hdr.index_offset, block_hdr.type, block_hdr.offset));
1524 
1525  if (block_hdr.index_offset == (uint16_t)0x0101) { //type 3
1526  size_t i;
1527  char *b_ptr = buf + 8;
1528  subblocks.subblock_count = block_hdr.type;
1529  subblocks.subs = malloc(sizeof(pst_subblock) * subblocks.subblock_count);
1530  for (i=0; i<subblocks.subblock_count; i++) {
1531  b_ptr += pst_decode_type3(pf, &table3_rec, b_ptr);
1532  subblocks.subs[i].buf = NULL;
1533  subblocks.subs[i].read_size = pst_ff_getIDblock_dec(pf, table3_rec.id, &subblocks.subs[i].buf);
1534  if (subblocks.subs[i].buf) {
1535  memcpy(&block_hdr, subblocks.subs[i].buf, sizeof(block_hdr));
1536  LE16_CPU(block_hdr.index_offset);
1537  subblocks.subs[i].i_offset = block_hdr.index_offset;
1538  }
1539  else {
1540  subblocks.subs[i].read_size = 0;
1541  subblocks.subs[i].i_offset = 0;
1542  }
1543  }
1544  free(buf);
1545  memcpy(&block_hdr, subblocks.subs[0].buf, sizeof(block_hdr));
1546  LE16_CPU(block_hdr.index_offset);
1547  LE16_CPU(block_hdr.type);
1548  LE32_CPU(block_hdr.offset);
1549  DEBUG_INFO(("block header (index_offset=%#hx, type=%#hx, offset=%#hx)\n", block_hdr.index_offset, block_hdr.type, block_hdr.offset));
1550  }
1551  else {
1552  // setup the subblock descriptors, but we only have one block
1553  subblocks.subblock_count = (size_t)1;
1554  subblocks.subs = malloc(sizeof(pst_subblock));
1555  subblocks.subs[0].buf = buf;
1556  subblocks.subs[0].read_size = read_size;
1557  subblocks.subs[0].i_offset = block_hdr.index_offset;
1558  }
1559 
1560  if (block_hdr.type == (uint16_t)0xBCEC) { //type 1
1561  block_type = 1;
1562 
1563  if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, block_hdr.offset, &block_offset1)) {
1564  DEBUG_WARN(("internal error (bc.b5 offset %#x) in reading block id %#"PRIx64"\n", block_hdr.offset, block_id));
1565  freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
1566  DEBUG_RET();
1567  return NULL;
1568  }
1569  memcpy(&table_rec, block_offset1.from, sizeof(table_rec));
1570  LE16_CPU(table_rec.type);
1571  LE16_CPU(table_rec.ref_type);
1572  LE32_CPU(table_rec.value);
1573  DEBUG_INFO(("table_rec (type=%#hx, ref_type=%#hx, value=%#x)\n", table_rec.type, table_rec.ref_type, table_rec.value));
1574 
1575  if ((table_rec.type != (uint16_t)0x02B5) || (table_rec.ref_type != 6)) {
1576  DEBUG_WARN(("Unknown second block constant - %#hx %#hx for id %#"PRIx64"\n", table_rec.type, table_rec.ref_type, block_id));
1577  freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
1578  DEBUG_RET();
1579  return NULL;
1580  }
1581 
1582  if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, table_rec.value, &block_offset2)) {
1583  DEBUG_WARN(("internal error (bc.b5.desc offset #x) in reading block id %#"PRIx64"\n", table_rec.value, block_id));
1584  freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
1585  DEBUG_RET();
1586  return NULL;
1587  }
1588  list_start = block_offset2.from;
1589  to_ptr = block_offset2.to;
1590  num_mapi_elements = (to_ptr - list_start)/sizeof(table_rec);
1591  num_mapi_objects = 1; // only going to be one object in these blocks
1592  }
1593  else if (block_hdr.type == (uint16_t)0x7CEC) { //type 2
1594  block_type = 2;
1595 
1596  if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, block_hdr.offset, &block_offset3)) {
1597  DEBUG_WARN(("internal error (7c.7c offset %#x) in reading block id %#"PRIx64"\n", block_hdr.offset, block_id));
1598  freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
1599  DEBUG_RET();
1600  return NULL;
1601  }
1602  fr_ptr = block_offset3.from; //now got pointer to "7C block"
1603  memset(&seven_c_blk, 0, sizeof(seven_c_blk));
1604  memcpy(&seven_c_blk, fr_ptr, sizeof(seven_c_blk));
1605  LE16_CPU(seven_c_blk.u1);
1606  LE16_CPU(seven_c_blk.u2);
1607  LE16_CPU(seven_c_blk.u3);
1608  LE16_CPU(seven_c_blk.rec_size);
1609  LE32_CPU(seven_c_blk.b_five_offset);
1610  LE32_CPU(seven_c_blk.ind2_offset);
1611  LE16_CPU(seven_c_blk.u7);
1612  LE16_CPU(seven_c_blk.u8);
1613 
1614  list_start = fr_ptr + sizeof(seven_c_blk); // the list of item numbers start after this record
1615 
1616  if (seven_c_blk.seven_c != 0x7C) { // this would mean it isn't a 7C block!
1617  DEBUG_WARN(("Error. There isn't a 7C where I want to see 7C!\n"));
1618  freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
1619  DEBUG_RET();
1620  return NULL;
1621  }
1622 
1623  rec_size = seven_c_blk.rec_size;
1624  num_mapi_elements = (int32_t)(unsigned)seven_c_blk.item_count;
1625 
1626  if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, seven_c_blk.b_five_offset, &block_offset4)) {
1627  DEBUG_WARN(("internal error (7c.b5 offset %#x) in reading block id %#"PRIx64"\n", seven_c_blk.b_five_offset, block_id));
1628  freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
1629  DEBUG_RET();
1630  return NULL;
1631  }
1632  memcpy(&table_rec, block_offset4.from, sizeof(table_rec));
1633  LE16_CPU(table_rec.type);
1634  LE16_CPU(table_rec.ref_type);
1635  LE32_CPU(table_rec.value);
1636  DEBUG_INFO(("table_rec (type=%#hx, ref_type=%#hx, value=%#x)\n", table_rec.type, table_rec.ref_type, table_rec.value));
1637 
1638  if (table_rec.type != (uint16_t)0x04B5) { // different constant than a type 1 record
1639  DEBUG_WARN(("Unknown second block constant - %#hx for id %#"PRIx64"\n", table_rec.type, block_id));
1640  freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
1641  DEBUG_RET();
1642  return NULL;
1643  }
1644 
1645  if (table_rec.value > 0) {
1646  if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, table_rec.value, &block_offset5)) {
1647  DEBUG_WARN(("internal error (7c.b5.desc offset %#x) in reading block id %#"PRIx64"\n", table_rec.value, block_id));
1648  freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
1649  DEBUG_RET();
1650  return NULL;
1651  }
1652 
1653  // this will give the number of records in this block
1654  num_mapi_objects = (block_offset5.to - block_offset5.from) / (4 + table_rec.ref_type);
1655 
1656  if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, seven_c_blk.ind2_offset, &block_offset6)) {
1657  DEBUG_WARN(("internal error (7c.ind2 offset %#x) in reading block id %#"PRIx64"\n", seven_c_blk.ind2_offset, block_id));
1658  freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
1659  DEBUG_RET();
1660  return NULL;
1661  }
1662  ind2_ptr = block_offset6.from;
1663  ind2_block_start = ind2_ptr;
1664  ind2_end = block_offset6.to;
1665  }
1666  else {
1667  num_mapi_objects = 0;
1668  }
1669  DEBUG_INFO(("7cec block index2 pointer %#x and end %#x\n", ind2_ptr, ind2_end));
1670  }
1671  else {
1672  DEBUG_WARN(("ERROR: Unknown block constant - %#hx for id %#"PRIx64"\n", block_hdr.type, block_id));
1673  freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
1674  DEBUG_RET();
1675  return NULL;
1676  }
1677 
1678  DEBUG_INFO(("found %i mapi objects each with %i mapi elements\n", num_mapi_objects, num_mapi_elements));
1679  for (count_mapi_objects=0; count_mapi_objects<num_mapi_objects; count_mapi_objects++) {
1680  // put another mapi object on the linked list
1681  mo_ptr = (pst_mapi_object*) pst_malloc(sizeof(pst_mapi_object));
1682  memset(mo_ptr, 0, sizeof(pst_mapi_object));
1683  mo_ptr->next = mo_head;
1684  mo_head = mo_ptr;
1685  // allocate the array of mapi elements
1686  mo_ptr->elements = (pst_mapi_element**) pst_malloc(sizeof(pst_mapi_element)*num_mapi_elements);
1687  mo_ptr->count_elements = num_mapi_elements;
1688  mo_ptr->orig_count = num_mapi_elements;
1689  mo_ptr->count_objects = (int32_t)num_mapi_objects; // each record will have a record of the total number of records
1690  for (x=0; x<num_mapi_elements; x++) mo_ptr->elements[x] = NULL;
1691 
1692  DEBUG_INFO(("going to read %i mapi elements for mapi object %i\n", num_mapi_elements, count_mapi_objects));
1693 
1694  fr_ptr = list_start; // initialize fr_ptr to the start of the list.
1695  x = 0; // x almost tracks count_mapi_elements, but see 'continue' statement below
1696  for (count_mapi_elements=0; count_mapi_elements<num_mapi_elements; count_mapi_elements++) { //we will increase fr_ptr as we progress through index
1697  char* value_pointer = NULL; // needed for block type 2 with values larger than 4 bytes
1698  size_t value_size = 0;
1699  if (block_type == 1) {
1700  memcpy(&table_rec, fr_ptr, sizeof(table_rec));
1701  LE16_CPU(table_rec.type);
1702  LE16_CPU(table_rec.ref_type);
1703  //LE32_CPU(table_rec.value); // done later, some may be order invariant
1704  fr_ptr += sizeof(table_rec);
1705  } else if (block_type == 2) {
1706  // we will copy the table2_rec values into a table_rec record so that we can keep the rest of the code
1707  memcpy(&table2_rec, fr_ptr, sizeof(table2_rec));
1708  LE16_CPU(table2_rec.ref_type);
1709  LE16_CPU(table2_rec.type);
1710  LE16_CPU(table2_rec.ind2_off);
1711  DEBUG_INFO(("reading element %i (type=%#x, ref_type=%#x, offset=%#x, size=%#x)\n",
1712  x, table2_rec.type, table2_rec.ref_type, table2_rec.ind2_off, table2_rec.size));
1713 
1714  // table_rec and table2_rec are arranged differently, so assign the values across
1715  table_rec.type = table2_rec.type;
1716  table_rec.ref_type = table2_rec.ref_type;
1717  table_rec.value = 0;
1718  if ((ind2_end - ind2_ptr) >= (int)(table2_rec.ind2_off + table2_rec.size)) {
1719  size_t n = table2_rec.size;
1720  size_t m = sizeof(table_rec.value);
1721  if (n <= m) {
1722  memcpy(&table_rec.value, ind2_ptr + table2_rec.ind2_off, n);
1723  }
1724  else {
1725  value_pointer = ind2_ptr + table2_rec.ind2_off;
1726  value_size = n;
1727  }
1728  //LE32_CPU(table_rec.value); // done later, some may be order invariant
1729  }
1730  else {
1731  DEBUG_WARN (("Trying to read outside buffer, buffer size %#x, offset %#x, data size %#x\n",
1732  read_size, ind2_end-ind2_ptr+table2_rec.ind2_off, table2_rec.size));
1733  }
1734  fr_ptr += sizeof(table2_rec);
1735  } else {
1736  DEBUG_WARN(("Missing code for block_type %i\n", block_type));
1737  freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
1738  pst_free_list(mo_head);
1739  DEBUG_RET();
1740  return NULL;
1741  }
1742  DEBUG_INFO(("reading element %i (type=%#x, ref_type=%#x, value=%#x)\n",
1743  x, table_rec.type, table_rec.ref_type, table_rec.value));
1744 
1745  if (!mo_ptr->elements[x]) {
1746  mo_ptr->elements[x] = (pst_mapi_element*) pst_malloc(sizeof(pst_mapi_element));
1747  }
1748  memset(mo_ptr->elements[x], 0, sizeof(pst_mapi_element)); //init it
1749 
1750  // check here to see if the id of the attribute is a mapped one
1751  mapptr = pf->x_head;
1752  while (mapptr && (mapptr->map < table_rec.type)) mapptr = mapptr->next;
1753  if (mapptr && (mapptr->map == table_rec.type)) {
1754  if (mapptr->mytype == PST_MAP_ATTRIB) {
1755  mo_ptr->elements[x]->mapi_id = *((uint32_t*)mapptr->data);
1756  DEBUG_INFO(("Mapped attrib %#x to %#x\n", table_rec.type, mo_ptr->elements[x]->mapi_id));
1757  } else if (mapptr->mytype == PST_MAP_HEADER) {
1758  DEBUG_INFO(("Internet Header mapping found %#"PRIx32" to %s\n", table_rec.type, mapptr->data));
1759  mo_ptr->elements[x]->mapi_id = (uint32_t)PST_ATTRIB_HEADER;
1760  mo_ptr->elements[x]->extra = mapptr->data;
1761  }
1762  else {
1763  DEBUG_WARN(("Missing assertion failure\n"));
1764  // nothing, should be assertion failure here
1765  }
1766  } else {
1767  mo_ptr->elements[x]->mapi_id = table_rec.type;
1768  }
1769  mo_ptr->elements[x]->type = 0; // checked later before it is set
1770  /* Reference Types
1771  0x0002 - Signed 16bit value
1772  0x0003 - Signed 32bit value
1773  0x0004 - 4-byte floating point
1774  0x0005 - Floating point double
1775  0x0006 - Signed 64-bit int
1776  0x0007 - Application Time
1777  0x000A - 32-bit error value
1778  0x000B - Boolean (non-zero = true)
1779  0x000D - Embedded Object
1780  0x0014 - 8-byte signed integer (64-bit)
1781  0x001E - Null terminated String
1782  0x001F - Unicode string
1783  0x0040 - Systime - Filetime structure
1784  0x0048 - OLE Guid
1785  0x0102 - Binary data
1786  0x1003 - Array of 32bit values
1787  0x1014 - Array of 64bit values
1788  0x101E - Array of Strings
1789  0x1102 - Array of Binary data
1790  */
1791 
1792  if (table_rec.ref_type == (uint16_t)0x0002 ||
1793  table_rec.ref_type == (uint16_t)0x0003 ||
1794  table_rec.ref_type == (uint16_t)0x000b) {
1795  //contains 32 bits of data
1796  mo_ptr->elements[x]->size = sizeof(int32_t);
1797  mo_ptr->elements[x]->type = table_rec.ref_type;
1798  mo_ptr->elements[x]->data = pst_malloc(sizeof(int32_t));
1799  memcpy(mo_ptr->elements[x]->data, &(table_rec.value), sizeof(int32_t));
1800  // are we missing an LE32_CPU() call here? table_rec.value is still
1801  // in the original order.
1802 
1803  } else if (table_rec.ref_type == (uint16_t)0x0005 ||
1804  table_rec.ref_type == (uint16_t)0x000d ||
1805  table_rec.ref_type == (uint16_t)0x0014 ||
1806  table_rec.ref_type == (uint16_t)0x001e ||
1807  table_rec.ref_type == (uint16_t)0x001f ||
1808  table_rec.ref_type == (uint16_t)0x0040 ||
1809  table_rec.ref_type == (uint16_t)0x0048 ||
1810  table_rec.ref_type == (uint16_t)0x0102 ||
1811  table_rec.ref_type == (uint16_t)0x1003 ||
1812  table_rec.ref_type == (uint16_t)0x1014 ||
1813  table_rec.ref_type == (uint16_t)0x101e ||
1814  table_rec.ref_type == (uint16_t)0x101f ||
1815  table_rec.ref_type == (uint16_t)0x1102) {
1816  //contains index reference to data
1817  LE32_CPU(table_rec.value);
1818  if (value_pointer) {
1819  // in a type 2 block, with a value that is more than 4 bytes
1820  // directly stored in this block.
1821  mo_ptr->elements[x]->size = value_size;
1822  mo_ptr->elements[x]->type = table_rec.ref_type;
1823  mo_ptr->elements[x]->data = pst_malloc(value_size);
1824  memcpy(mo_ptr->elements[x]->data, value_pointer, value_size);
1825  }
1826  else if (pst_getBlockOffsetPointer(pf, i2_head, &subblocks, table_rec.value, &block_offset7)) {
1827  if ((table_rec.value & 0xf) == (uint32_t)0xf) {
1828  DEBUG_WARN(("failed to get block offset for table_rec.value of %#x to be read later.\n", table_rec.value));
1829  mo_ptr->elements[x]->size = 0;
1830  mo_ptr->elements[x]->data = NULL;
1831  mo_ptr->elements[x]->type = table_rec.value;
1832  }
1833  else {
1834  if (table_rec.value) {
1835  DEBUG_WARN(("failed to get block offset for table_rec.value of %#x\n", table_rec.value));
1836  }
1837  mo_ptr->count_elements --; //we will be skipping a row
1838  continue;
1839  }
1840  }
1841  else {
1842  value_size = (size_t)(block_offset7.to - block_offset7.from);
1843  mo_ptr->elements[x]->size = value_size;
1844  mo_ptr->elements[x]->type = table_rec.ref_type;
1845  mo_ptr->elements[x]->data = pst_malloc(value_size+1);
1846  memcpy(mo_ptr->elements[x]->data, block_offset7.from, value_size);
1847  mo_ptr->elements[x]->data[value_size] = '\0'; // it might be a string, null terminate it.
1848  }
1849  if (table_rec.ref_type == (uint16_t)0xd) {
1850  // there is still more to do for the type of 0xD embedded objects
1851  type_d_rec = (struct _type_d_rec*) mo_ptr->elements[x]->data;
1852  LE32_CPU(type_d_rec->id);
1853  mo_ptr->elements[x]->size = pst_ff_getID2block(pf, type_d_rec->id, i2_head, &(mo_ptr->elements[x]->data));
1854  if (!mo_ptr->elements[x]->size){
1855  DEBUG_WARN(("not able to read the ID2 data. Setting to be read later. %#x\n", type_d_rec->id));
1856  mo_ptr->elements[x]->type = type_d_rec->id; // fetch before freeing data, alias pointer
1857  free(mo_ptr->elements[x]->data);
1858  mo_ptr->elements[x]->data = NULL;
1859  }
1860  }
1861  if (table_rec.ref_type == (uint16_t)0x1f) {
1862  // there is more to do for the type 0x1f unicode strings
1863  size_t rc;
1864  static pst_vbuf *utf16buf = NULL;
1865  static pst_vbuf *utf8buf = NULL;
1866  if (!utf16buf) utf16buf = pst_vballoc((size_t)1024);
1867  if (!utf8buf) utf8buf = pst_vballoc((size_t)1024);
1868 
1869  //need UTF-16 zero-termination
1870  pst_vbset(utf16buf, mo_ptr->elements[x]->data, mo_ptr->elements[x]->size);
1871  pst_vbappend(utf16buf, "\0\0", (size_t)2);
1872  DEBUG_INFO(("Iconv in:\n"));
1873  DEBUG_HEXDUMPC(utf16buf->b, utf16buf->dlen, 0x10);
1874  rc = pst_vb_utf16to8(utf8buf, utf16buf->b, utf16buf->dlen);
1875  if (rc == (size_t)-1) {
1876  DEBUG_WARN(("Failed to convert utf-16 to utf-8\n"));
1877  }
1878  else {
1879  free(mo_ptr->elements[x]->data);
1880  mo_ptr->elements[x]->size = utf8buf->dlen;
1881  mo_ptr->elements[x]->data = pst_malloc(utf8buf->dlen);
1882  memcpy(mo_ptr->elements[x]->data, utf8buf->b, utf8buf->dlen);
1883  }
1884  DEBUG_INFO(("Iconv out:\n"));
1885  DEBUG_HEXDUMPC(mo_ptr->elements[x]->data, mo_ptr->elements[x]->size, 0x10);
1886  }
1887  if (mo_ptr->elements[x]->type == 0) mo_ptr->elements[x]->type = table_rec.ref_type;
1888  } else {
1889  DEBUG_WARN(("ERROR Unknown ref_type %#hx\n", table_rec.ref_type));
1890  }
1891  x++;
1892  }
1893  DEBUG_INFO(("increasing ind2_ptr by %i [%#x] bytes. Was %#x, Now %#x\n", rec_size, rec_size, ind2_ptr, ind2_ptr+rec_size));
1894  ind2_ptr += rec_size;
1895  // ind2 rows do not get split between blocks. See PST spec, 2.3.4.4 "Row Matrix".
1896  if (ind2_ptr + rec_size > ind2_block_start + ind2_max_block_size) {
1897  ind2_block_start += ind2_max_block_size;
1898  DEBUG_INFO(("advancing ind2_ptr to next block. Was %#x, Now %#x\n", ind2_ptr, ind2_block_start));
1899  ind2_ptr = ind2_block_start;
1900  }
1901  }
1902  freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
1903  DEBUG_RET();
1904  return mo_head;
1905 }
1906 
1907 
1908 // This version of free does NULL check first
1909 #define SAFE_FREE(x) {if (x) free(x);}
1910 #define SAFE_FREE_STR(x) SAFE_FREE(x.str)
1911 #define SAFE_FREE_BIN(x) SAFE_FREE(x.data)
1912 
1913 // check if item->email is NULL, and init if so
1914 #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) );} }
1915 #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) );} }
1916 #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) );} }
1917 #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));} }
1918 #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) );} }
1919 #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) );} }
1920 
1921 // malloc space and copy the current item's data null terminated
1922 #define LIST_COPY(targ, type) { \
1923  targ = type pst_realloc(targ, list->elements[x]->size+1); \
1924  memcpy(targ, list->elements[x]->data, list->elements[x]->size);\
1925  memset(((char*)targ)+list->elements[x]->size, 0, (size_t)1); \
1926 }
1927 
1928 #define LIST_COPY_CSTR(targ) { \
1929  if ((list->elements[x]->type == 0x1f) || \
1930  (list->elements[x]->type == 0x1e) || \
1931  (list->elements[x]->type == 0x102)) { \
1932  LIST_COPY(targ, (char*)) \
1933  } \
1934  else { \
1935  DEBUG_WARN(("src not 0x1e or 0x1f or 0x102 for string dst\n")); \
1936  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size); \
1937  SAFE_FREE(targ); \
1938  targ = NULL; \
1939  } \
1940 }
1941 
1942 #define LIST_COPY_BOOL(label, targ) { \
1943  if (list->elements[x]->type != 0x0b) { \
1944  DEBUG_WARN(("src not 0x0b for boolean dst\n")); \
1945  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size); \
1946  } \
1947  if (*(int16_t*)list->elements[x]->data) { \
1948  DEBUG_INFO((label" - True\n")); \
1949  targ = 1; \
1950  } else { \
1951  DEBUG_INFO((label" - False\n")); \
1952  targ = 0; \
1953  } \
1954 }
1955 
1956 #define LIST_COPY_EMAIL_BOOL(label, targ) { \
1957  MALLOC_EMAIL(item); \
1958  LIST_COPY_BOOL(label, targ) \
1959 }
1960 
1961 #define LIST_COPY_CONTACT_BOOL(label, targ) { \
1962  MALLOC_CONTACT(item); \
1963  LIST_COPY_BOOL(label, targ) \
1964 }
1965 
1966 #define LIST_COPY_APPT_BOOL(label, targ) { \
1967  MALLOC_APPOINTMENT(item); \
1968  LIST_COPY_BOOL(label, targ) \
1969 }
1970 
1971 #define LIST_COPY_INT16_N(targ) { \
1972  if (list->elements[x]->type != 0x02) { \
1973  DEBUG_WARN(("src not 0x02 for int16 dst\n")); \
1974  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size); \
1975  } \
1976  memcpy(&(targ), list->elements[x]->data, sizeof(targ)); \
1977  LE16_CPU(targ); \
1978 }
1979 
1980 #define LIST_COPY_INT16(label, targ) { \
1981  LIST_COPY_INT16_N(targ); \
1982  DEBUG_INFO((label" - %i %#x\n", (int)targ, (int)targ)); \
1983 }
1984 
1985 #define LIST_COPY_INT32_N(targ) { \
1986  if (list->elements[x]->type != 0x03) { \
1987  DEBUG_WARN(("src not 0x03 for int32 dst\n")); \
1988  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size); \
1989  } \
1990  memcpy(&(targ), list->elements[x]->data, sizeof(targ)); \
1991  LE32_CPU(targ); \
1992 }
1993 
1994 #define LIST_COPY_INT32(label, targ) { \
1995  LIST_COPY_INT32_N(targ); \
1996  DEBUG_INFO((label" - %i %#x\n", (int)targ, (int)targ)); \
1997 }
1998 
1999 #define LIST_COPY_EMAIL_INT32(label, targ) { \
2000  MALLOC_EMAIL(item); \
2001  LIST_COPY_INT32(label, targ); \
2002 }
2003 
2004 #define LIST_COPY_APPT_INT32(label, targ) { \
2005  MALLOC_APPOINTMENT(item); \
2006  LIST_COPY_INT32(label, targ); \
2007 }
2008 
2009 #define LIST_COPY_FOLDER_INT32(label, targ) { \
2010  MALLOC_FOLDER(item); \
2011  LIST_COPY_INT32(label, targ); \
2012 }
2013 
2014 #define LIST_COPY_STORE_INT32(label, targ) { \
2015  MALLOC_MESSAGESTORE(item); \
2016  LIST_COPY_INT32(label, targ); \
2017 }
2018 
2019 #define LIST_COPY_ENUM(label, targ, delta, count, ...) { \
2020  char *tlabels[] = {__VA_ARGS__}; \
2021  LIST_COPY_INT32_N(targ); \
2022  targ += delta; \
2023  DEBUG_INFO((label" - %s [%i]\n", \
2024  (((int)targ < 0) || ((int)targ >= count)) \
2025  ? "**invalid" \
2026  : tlabels[(int)targ], (int)targ)); \
2027 }
2028 
2029 #define LIST_COPY_EMAIL_ENUM(label, targ, delta, count, ...) { \
2030  MALLOC_EMAIL(item); \
2031  LIST_COPY_ENUM(label, targ, delta, count, __VA_ARGS__); \
2032 }
2033 
2034 #define LIST_COPY_APPT_ENUM(label, targ, delta, count, ...) { \
2035  MALLOC_APPOINTMENT(item); \
2036  LIST_COPY_ENUM(label, targ, delta, count, __VA_ARGS__); \
2037 }
2038 
2039 #define LIST_COPY_ENUM16(label, targ, delta, count, ...) { \
2040  char *tlabels[] = {__VA_ARGS__}; \
2041  LIST_COPY_INT16_N(targ); \
2042  targ += delta; \
2043  DEBUG_INFO((label" - %s [%i]\n", \
2044  (((int)targ < 0) || ((int)targ >= count)) \
2045  ? "**invalid" \
2046  : tlabels[(int)targ], (int)targ)); \
2047 }
2048 
2049 #define LIST_COPY_CONTACT_ENUM16(label, targ, delta, count, ...) { \
2050  MALLOC_CONTACT(item); \
2051  LIST_COPY_ENUM16(label, targ, delta, count, __VA_ARGS__); \
2052 }
2053 
2054 #define LIST_COPY_ENTRYID(label, targ) { \
2055  LIST_COPY(targ, (pst_entryid*)); \
2056  LE32_CPU(targ->u1); \
2057  LE32_CPU(targ->id); \
2058  DEBUG_INFO((label" u1=%#x, id=%#x\n", targ->u1, targ->id)); \
2059 }
2060 
2061 #define LIST_COPY_EMAIL_ENTRYID(label, targ) { \
2062  MALLOC_EMAIL(item); \
2063  LIST_COPY_ENTRYID(label, targ); \
2064 }
2065 
2066 #define LIST_COPY_STORE_ENTRYID(label, targ) { \
2067  MALLOC_MESSAGESTORE(item); \
2068  LIST_COPY_ENTRYID(label, targ); \
2069 }
2070 
2071 
2072 // malloc space and copy the current item's data null terminated
2073 // including the utf8 flag
2074 #define LIST_COPY_STR(label, targ) { \
2075  LIST_COPY_CSTR(targ.str); \
2076  targ.is_utf8 = (list->elements[x]->type == 0x1f) ? 1 : 0; \
2077  DEBUG_INFO((label" - unicode %d - %s\n", targ.is_utf8, targ.str)); \
2078 }
2079 
2080 #define LIST_COPY_EMAIL_STR(label, targ) { \
2081  MALLOC_EMAIL(item); \
2082  LIST_COPY_STR(label, targ); \
2083 }
2084 
2085 #define LIST_COPY_CONTACT_STR(label, targ) { \
2086  MALLOC_CONTACT(item); \
2087  LIST_COPY_STR(label, targ); \
2088 }
2089 
2090 #define LIST_COPY_APPT_STR(label, targ) { \
2091  MALLOC_APPOINTMENT(item); \
2092  LIST_COPY_STR(label, targ); \
2093 }
2094 
2095 #define LIST_COPY_JOURNAL_STR(label, targ) { \
2096  MALLOC_JOURNAL(item); \
2097  LIST_COPY_STR(label, targ); \
2098 }
2099 
2100 // malloc space and copy the item filetime
2101 #define LIST_COPY_TIME(label, targ) { \
2102  if ((list->elements[x]->type != 0x40) || \
2103  (list->elements[x]->size != sizeof(FILETIME))) { \
2104  DEBUG_WARN(("src not 0x40 or wrong length for filetime dst\n")); \
2105  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size); \
2106  } \
2107  else { \
2108  targ = (FILETIME*) pst_realloc(targ, sizeof(FILETIME)); \
2109  memcpy(targ, list->elements[x]->data, sizeof(FILETIME)); \
2110  LE32_CPU(targ->dwLowDateTime); \
2111  LE32_CPU(targ->dwHighDateTime); \
2112  DEBUG_INFO((label" - %s", pst_fileTimeToAscii(targ, time_buffer))); \
2113  } \
2114 }
2115 
2116 #define LIST_COPY_EMAIL_TIME(label, targ) { \
2117  MALLOC_EMAIL(item); \
2118  LIST_COPY_TIME(label, targ); \
2119 }
2120 
2121 #define LIST_COPY_CONTACT_TIME(label, targ) { \
2122  MALLOC_CONTACT(item); \
2123  LIST_COPY_TIME(label, targ); \
2124 }
2125 
2126 #define LIST_COPY_APPT_TIME(label, targ) { \
2127  MALLOC_APPOINTMENT(item); \
2128  LIST_COPY_TIME(label, targ); \
2129 }
2130 
2131 #define LIST_COPY_JOURNAL_TIME(label, targ) { \
2132  MALLOC_JOURNAL(item); \
2133  LIST_COPY_TIME(label, targ); \
2134 }
2135 
2136 // malloc space and copy the current item's data and size
2137 #define LIST_COPY_BIN(targ) { \
2138  targ.size = list->elements[x]->size; \
2139  if (targ.size) { \
2140  targ.data = (char*)pst_realloc(targ.data, targ.size); \
2141  memcpy(targ.data, list->elements[x]->data, targ.size); \
2142  } \
2143  else { \
2144  SAFE_FREE_BIN(targ); \
2145  targ.data = NULL; \
2146  } \
2147 }
2148 
2149 #define LIST_COPY_EMAIL_BIN(label, targ) { \
2150  MALLOC_EMAIL(item); \
2151  LIST_COPY_BIN(targ); \
2152  DEBUG_INFO((label"\n")); \
2153 }
2154 #define LIST_COPY_APPT_BIN(label, targ) { \
2155  MALLOC_APPOINTMENT(item); \
2156  LIST_COPY_BIN(targ); \
2157  DEBUG_INFO((label"\n")); \
2158  DEBUG_HEXDUMP(targ.data, targ.size); \
2159 }
2160 
2161 #define NULL_CHECK(x) { if (!x) { DEBUG_WARN(("NULL_CHECK: Null Found\n")); break;} }
2162 
2163 
2179 static int pst_process(uint64_t block_id, pst_mapi_object *list, pst_item *item, pst_item_attach *attach) {
2180  DEBUG_ENT("pst_process");
2181  if (!item) {
2182  DEBUG_WARN(("item cannot be NULL.\n"));
2183  DEBUG_RET();
2184  return -1;
2185  }
2186 
2187  item->block_id = block_id;
2188  while (list) {
2189  int32_t x;
2190  char time_buffer[30];
2191  for (x=0; x<list->count_elements; x++) {
2192  int32_t t;
2193  uint32_t ut;
2194  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));
2195 
2196  switch (list->elements[x]->mapi_id) {
2197  case PST_ATTRIB_HEADER: // CUSTOM attribute for saying the Extra Headers
2198  if (list->elements[x]->extra) {
2199  if (list->elements[x]->type == 0x0101e) {
2200  // an array of strings, rather than a single string
2201  int32_t string_length, i, offset, next_offset;
2202  int32_t p = 0;
2203  int32_t array_element_count = PST_LE_GET_INT32(list->elements[x]->data); p+=4;
2204  for (i = 1; i <= array_element_count; i++) {
2206  memset(ef, 0, sizeof(pst_item_extra_field));
2207  offset = PST_LE_GET_INT32(list->elements[x]->data + p); p+=4;
2208  next_offset = (i == array_element_count) ? list->elements[x]->size : PST_LE_GET_INT32(list->elements[x]->data + p);;
2209  string_length = next_offset - offset;
2210  ef->value = pst_malloc(string_length + 1);
2211  memcpy(ef->value, list->elements[x]->data + offset, string_length);
2212  ef->value[string_length] = '\0';
2213  ef->field_name = strdup(list->elements[x]->extra);
2214  ef->next = item->extra_fields;
2215  item->extra_fields = ef;
2216  DEBUG_INFO(("Extra Field - \"%s\" = \"%s\"\n", ef->field_name, ef->value));
2217  }
2218  }
2219  else {
2220  // should be a single string
2222  memset(ef, 0, sizeof(pst_item_extra_field));
2223  LIST_COPY_CSTR(ef->value);
2224  if (ef->value) {
2225  ef->field_name = strdup(list->elements[x]->extra);
2226  ef->next = item->extra_fields;
2227  item->extra_fields = ef;
2228  DEBUG_INFO(("Extra Field - \"%s\" = \"%s\"\n", ef->field_name, ef->value));
2229  if (strcmp(ef->field_name, "content-type") == 0) {
2230  char *p = strstr(ef->value, "charset=\"");
2231  if (p) {
2232  p += 9; // skip over charset="
2233  char *pp = strchr(p, '"');
2234  if (pp) {
2235  *pp = '\0';
2236  char *set = strdup(p);
2237  *pp = '"';
2238  if (item->body_charset.str) free(item->body_charset.str);
2239  item->body_charset.str = set;
2240  item->body_charset.is_utf8 = 1;
2241  DEBUG_INFO(("body charset %s from content-type extra field\n", set));
2242  }
2243  }
2244  }
2245  }
2246  else {
2247  DEBUG_WARN(("What does this mean? Internet header %s value\n", list->elements[x]->extra));
2248  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
2249  free(ef); // caught by valgrind
2250  }
2251  }
2252  }
2253  break;
2254  case 0x0002: // PR_ALTERNATE_RECIPIENT_ALLOWED
2255  if (list->elements[x]->type == 0x0b) {
2256  // If set to true, the sender allows this email to be autoforwarded
2257  LIST_COPY_EMAIL_BOOL("AutoForward allowed", item->email->autoforward);
2258  if (!item->email->autoforward) item->email->autoforward = -1;
2259  } else {
2260  DEBUG_WARN(("What does this mean?\n"));
2261  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
2262  }
2263  break;
2264  case 0x0003: // Extended Attributes table
2265  DEBUG_INFO(("Extended Attributes Table - NOT PROCESSED\n"));
2266  break;
2267  case 0x0017: // PR_IMPORTANCE - How important the sender deems it to be
2268  LIST_COPY_EMAIL_ENUM("Importance Level", item->email->importance, 0, 3, "Low", "Normal", "High");
2269  break;
2270  case 0x001A: // PR_MESSAGE_CLASS IPM.x
2271  if ((list->elements[x]->type == 0x1e) ||
2272  (list->elements[x]->type == 0x1f)) {
2273  LIST_COPY_CSTR(item->ascii_type);
2274  if (!item->ascii_type) item->ascii_type = strdup("unknown");
2275  if (pst_strincmp("IPM.Note", item->ascii_type, 8) == 0)
2276  item->type = PST_TYPE_NOTE;
2277  else if (pst_stricmp("IPM", item->ascii_type) == 0)
2278  item->type = PST_TYPE_NOTE;
2279  else if (pst_strincmp("IPM.Contact", item->ascii_type, 11) == 0)
2280  item->type = PST_TYPE_CONTACT;
2281  else if (pst_strincmp("REPORT.IPM.Note", item->ascii_type, 15) == 0)
2282  item->type = PST_TYPE_REPORT;
2283  else if (pst_strincmp("IPM.Activity", item->ascii_type, 12) == 0)
2284  item->type = PST_TYPE_JOURNAL;
2285  else if (pst_strincmp("IPM.Appointment", item->ascii_type, 15) == 0)
2286  item->type = PST_TYPE_APPOINTMENT;
2287  else if (pst_strincmp("IPM.Schedule.Meeting", item->ascii_type, 20) == 0)
2288  item->type = PST_TYPE_SCHEDULE; // meeting requests and responses transported over email
2289  else if (pst_strincmp("IPM.StickyNote", item->ascii_type, 14) == 0)
2290  item->type = PST_TYPE_STICKYNOTE;
2291  else if (pst_strincmp("IPM.Task", item->ascii_type, 8) == 0)
2292  item->type = PST_TYPE_TASK;
2293  else
2294  item->type = PST_TYPE_OTHER;
2295  DEBUG_INFO(("Message class %s [%"PRIi32"] \n", item->ascii_type, item->type));
2296  }
2297  else {
2298  DEBUG_WARN(("What does this mean?\n"));
2299  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
2300  }
2301  break;
2302  case 0x0023: // PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED
2303  if (list->elements[x]->type == 0x0b) {
2304  // set if the sender wants a delivery report from all recipients
2305  LIST_COPY_EMAIL_BOOL("Global Delivery Report", item->email->delivery_report);
2306  }
2307  else {
2308  DEBUG_WARN(("What does this mean?\n"));
2309  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
2310  }
2311  break;
2312  case 0x0026: // PR_PRIORITY
2313  LIST_COPY_EMAIL_ENUM("Priority", item->email->priority, 1, 3, "NonUrgent", "Normal", "Urgent");
2314  break;
2315  case 0x0029: // PR_READ_RECEIPT_REQUESTED
2316  LIST_COPY_EMAIL_BOOL("Read Receipt", item->email->read_receipt);
2317  break;
2318  case 0x002B: // PR_RECIPIENT_REASSIGNMENT_PROHIBITED
2319  LIST_COPY_BOOL("Reassignment Prohibited (Private)", item->private_member);
2320  break;
2321  case 0x002E: // PR_ORIGINAL_SENSITIVITY - the sensitivity of the message before being replied to or forwarded
2322  LIST_COPY_EMAIL_ENUM("Original Sensitivity", item->email->original_sensitivity, 0, 4,
2323  "None", "Personal", "Private", "Company Confidential");
2324  break;
2325  case 0x0032: // PR_REPORT_TIME
2326  LIST_COPY_EMAIL_TIME("Report time", item->email->report_time);
2327  break;
2328  case 0x0036: // PR_SENSITIVITY - sender's opinion of the sensitivity of an email
2329  LIST_COPY_EMAIL_ENUM("Sensitivity", item->email->sensitivity, 0, 4,
2330  "None", "Personal", "Private", "Company Confidential");
2331  break;
2332  case 0x0037: // PR_SUBJECT raw subject
2333  {
2334  int off = 0;
2335  if ((list->elements[x]->size > 2) && (((uint8_t)list->elements[x]->data[0]) < 0x20)) {
2336  off = 2;
2337  }
2338  list->elements[x]->data += off;
2339  list->elements[x]->size -= off;
2340  LIST_COPY_STR("Raw Subject", item->subject);
2341  list->elements[x]->size += off;
2342  list->elements[x]->data -= off;
2343  }
2344  break;
2345  case 0x0039: // PR_CLIENT_SUBMIT_TIME Date Email Sent/Created
2346  LIST_COPY_EMAIL_TIME("Date sent", item->email->sent_date);
2347  break;
2348  case 0x003B: // PR_SENT_REPRESENTING_SEARCH_KEY Sender address 1
2349  LIST_COPY_EMAIL_STR("Sent on behalf of address 1", item->email->outlook_sender);
2350  break;
2351  case 0x003F: // PR_RECEIVED_BY_ENTRYID Structure containing Recipient
2352  DEBUG_INFO(("Recipient Structure 1 -- NOT PROCESSED\n"));
2353  break;
2354  case 0x0040: // PR_RECEIVED_BY_NAME Name of Recipient Structure
2355  LIST_COPY_EMAIL_STR("Received By Name 1", item->email->outlook_received_name1);
2356  break;
2357  case 0x0041: // PR_SENT_REPRESENTING_ENTRYID Structure containing Sender
2358  DEBUG_INFO(("Sent on behalf of Structure 1 -- NOT PROCESSED\n"));
2359  break;
2360  case 0x0042: // PR_SENT_REPRESENTING_NAME
2361  LIST_COPY_EMAIL_STR("Sent on behalf of", item->email->outlook_sender_name);
2362  break;
2363  case 0x0043: // PR_RCVD_REPRESENTING_ENTRYID Recipient Structure 2
2364  DEBUG_INFO(("Received on behalf of Structure -- NOT PROCESSED\n"));
2365  break;
2366  case 0x0044: // PR_RCVD_REPRESENTING_NAME
2367  LIST_COPY_EMAIL_STR("Received on behalf of", item->email->outlook_recipient_name);
2368  break;
2369  case 0x004F: // PR_REPLY_RECIPIENT_ENTRIES Reply-To Structure
2370  DEBUG_INFO(("Reply-To Structure -- NOT PROCESSED\n"));
2371  break;
2372  case 0x0050: // PR_REPLY_RECIPIENT_NAMES Name of Reply-To Structure
2373  LIST_COPY_EMAIL_STR("Reply-To", item->email->reply_to);
2374  break;
2375  case 0x0051: // PR_RECEIVED_BY_SEARCH_KEY Recipient Address 1
2376  LIST_COPY_EMAIL_STR("Recipient's Address 1", item->email->outlook_recipient);
2377  break;
2378  case 0x0052: // PR_RCVD_REPRESENTING_SEARCH_KEY Recipient Address 2
2379  LIST_COPY_EMAIL_STR("Recipient's Address 2", item->email->outlook_recipient2);
2380  break;
2381  case 0x0057: // PR_MESSAGE_TO_ME
2382  // this user is listed explicitly in the TO address
2383  LIST_COPY_EMAIL_BOOL("My address in TO field", item->email->message_to_me);
2384  break;
2385  case 0x0058: // PR_MESSAGE_CC_ME
2386  // this user is listed explicitly in the CC address
2387  LIST_COPY_EMAIL_BOOL("My address in CC field", item->email->message_cc_me);
2388  break;
2389  case 0x0059: // PR_MESSAGE_RECIP_ME
2390  // this user appears in TO, CC or BCC address list
2391  LIST_COPY_EMAIL_BOOL("Message addressed to me", item->email->message_recip_me);
2392  break;
2393  case 0x0063: // PR_RESPONSE_REQUESTED
2394  LIST_COPY_BOOL("Response requested", item->response_requested);
2395  break;
2396  case 0x0064: // PR_SENT_REPRESENTING_ADDRTYPE Access method for Sender Address
2397  LIST_COPY_EMAIL_STR("Sent on behalf of address type", item->email->sender_access);
2398  break;
2399  case 0x0065: // PR_SENT_REPRESENTING_EMAIL_ADDRESS Sender Address
2400  LIST_COPY_EMAIL_STR("Sent on behalf of address", item->email->sender_address);
2401  break;
2402  case 0x0070: // PR_CONVERSATION_TOPIC Processed Subject
2403  LIST_COPY_EMAIL_STR("Processed Subject (Conversation Topic)", item->email->processed_subject);
2404  break;
2405  case 0x0071: // PR_CONVERSATION_INDEX
2406  LIST_COPY_EMAIL_BIN("Conversation Index", item->email->conversation_index);
2407  break;
2408  case 0x0072: // PR_ORIGINAL_DISPLAY_BCC
2409  LIST_COPY_EMAIL_STR("Original display bcc", item->email->original_bcc);
2410  break;
2411  case 0x0073: // PR_ORIGINAL_DISPLAY_CC
2412  LIST_COPY_EMAIL_STR("Original display cc", item->email->original_cc);
2413  break;
2414  case 0x0074: // PR_ORIGINAL_DISPLAY_TO
2415  LIST_COPY_EMAIL_STR("Original display to", item->email->original_to);
2416  break;
2417  case 0x0075: // PR_RECEIVED_BY_ADDRTYPE Recipient Access Method
2418  LIST_COPY_EMAIL_STR("Received by Address type", item->email->recip_access);
2419  break;
2420  case 0x0076: // PR_RECEIVED_BY_EMAIL_ADDRESS Recipient Address
2421  LIST_COPY_EMAIL_STR("Received by Address", item->email->recip_address);
2422  break;
2423  case 0x0077: // PR_RCVD_REPRESENTING_ADDRTYPE Recipient Access Method 2
2424  LIST_COPY_EMAIL_STR("Received on behalf of Address type", item->email->recip2_access);
2425  break;
2426  case 0x0078: // PR_RCVD_REPRESENTING_EMAIL_ADDRESS Recipient Address 2
2427  LIST_COPY_EMAIL_STR("Received on behalf of Address", item->email->recip2_address);
2428  break;
2429  case 0x007D: // PR_TRANSPORT_MESSAGE_HEADERS Internet Header
2430  LIST_COPY_EMAIL_STR("Internet Header", item->email->header);
2431  break;
2432  case 0x0C04: // PR_NDR_REASON_CODE
2433  LIST_COPY_EMAIL_INT32("NDR reason code", item->email->ndr_reason_code);
2434  break;
2435  case 0x0C05: // PR_NDR_DIAG_CODE
2436  LIST_COPY_EMAIL_INT32("NDR diag code", item->email->ndr_diag_code);
2437  break;
2438  case 0x0C06: // PR_NON_RECEIPT_NOTIFICATION_REQUESTED
2439  DEBUG_INFO(("Non-Receipt Notification Requested -- NOT PROCESSED\n"));
2440  break;
2441  case 0x0C17: // PR_REPLY_REQUESTED
2442  LIST_COPY_EMAIL_BOOL("Reply Requested", item->email->reply_requested);
2443  break;
2444  case 0x0C19: // PR_SENDER_ENTRYID Sender Structure 2
2445  DEBUG_INFO(("Sender Structure 2 -- NOT PROCESSED\n"));
2446  break;
2447  case 0x0C1A: // PR_SENDER_NAME Name of Sender Structure 2
2448  LIST_COPY_EMAIL_STR("Name of Sender Structure 2", item->email->outlook_sender_name2);
2449  break;
2450  case 0x0C1B: // PR_SUPPLEMENTARY_INFO
2451  LIST_COPY_EMAIL_STR("Supplementary info", item->email->supplementary_info);
2452  break;
2453  case 0x0C1D: // PR_SENDER_SEARCH_KEY Name of Sender Address 2
2454  LIST_COPY_EMAIL_STR("Name of Sender Address 2 (Sender search key)", item->email->outlook_sender2);
2455  break;
2456  case 0x0C1E: // PR_SENDER_ADDRTYPE Sender Address 2 access method
2457  LIST_COPY_EMAIL_STR("Sender Address type", item->email->sender2_access);
2458  break;
2459  case 0x0C1F: // PR_SENDER_EMAIL_ADDRESS Sender Address 2
2460  LIST_COPY_EMAIL_STR("Sender Address", item->email->sender2_address);
2461  break;
2462  case 0x0C20: // PR_NDR_STATUS_CODE
2463  LIST_COPY_EMAIL_INT32("NDR status code", item->email->ndr_status_code);
2464  break;
2465  case 0x0E01: // PR_DELETE_AFTER_SUBMIT
2466  LIST_COPY_EMAIL_BOOL("Delete after submit", item->email->delete_after_submit);
2467  break;
2468  case 0x0E02: // PR_DISPLAY_BCC BCC Addresses
2469  LIST_COPY_EMAIL_STR("Display BCC Addresses", item->email->bcc_address);
2470  break;
2471  case 0x0E03: // PR_DISPLAY_CC CC Addresses
2472  LIST_COPY_EMAIL_STR("Display CC Addresses", item->email->cc_address);
2473  break;
2474  case 0x0E04: // PR_DISPLAY_TO Address Sent-To
2475  LIST_COPY_EMAIL_STR("Display Sent-To Address", item->email->sentto_address);
2476  break;
2477  case 0x0E06: // PR_MESSAGE_DELIVERY_TIME Date 3 - Email Arrival Date
2478  LIST_COPY_EMAIL_TIME("Date 3 (Delivery Time)", item->email->arrival_date);
2479  break;
2480  case 0x0E07: // PR_MESSAGE_FLAGS Email Flag
2481  LIST_COPY_EMAIL_INT32("Message Flags", item->flags);
2482  break;
2483  case 0x0E08: // PR_MESSAGE_SIZE Total size of a message object
2484  LIST_COPY_INT32("Message Size", item->message_size);
2485  break;
2486  case 0x0E0A: // PR_SENTMAIL_ENTRYID
2487  // folder that this message is sent to after submission
2488  LIST_COPY_EMAIL_ENTRYID("Sentmail EntryID", item->email->sentmail_folder);
2489  break;
2490  case 0x0E1D: // PR_NORMALIZED_SUBJECT
2491  LIST_COPY_EMAIL_STR("Normalized subject", item->email->outlook_normalized_subject);
2492  break;
2493  case 0x0E1F: // PR_RTF_IN_SYNC
2494  // True means that the rtf version is same as text body
2495  // False means rtf version is more up-to-date than text body
2496  // if this value doesn't exist, text body is more up-to-date than rtf and
2497  // cannot update to the rtf
2498  LIST_COPY_EMAIL_BOOL("Compressed RTF in Sync", item->email->rtf_in_sync);
2499  break;
2500  case 0x0E20: // PR_ATTACH_SIZE binary Attachment data in record
2501  NULL_CHECK(attach);
2502  LIST_COPY_INT32("Attachment Size", t);
2503  // ignore this. we either get data and size from 0x3701
2504  // or id codes from 0x3701 or 0x67f2
2505  break;
2506  case 0x0FF9: // PR_RECORD_KEY Record Header 1
2507  LIST_COPY_BIN(item->record_key);
2508  DEBUG_INFO(("Record Key\n"));
2510  break;
2511  case 0x1000: // PR_BODY
2512  LIST_COPY_STR("Plain Text body", item->body);
2513  break;
2514  case 0x1001: // PR_REPORT_TEXT
2515  LIST_COPY_EMAIL_STR("Report Text", item->email->report_text);
2516  break;
2517  case 0x1006: // PR_RTF_SYNC_BODY_CRC
2518  LIST_COPY_EMAIL_INT32("RTF Sync Body CRC", item->email->rtf_body_crc);
2519  break;
2520  case 0x1007: // PR_RTF_SYNC_BODY_COUNT
2521  // a count of the *significant* characters in the rtf body. Doesn't count
2522  // whitespace and other ignorable characters
2523  LIST_COPY_EMAIL_INT32("RTF Sync Body character count", item->email->rtf_body_char_count);
2524  break;
2525  case 0x1008: // PR_RTF_SYNC_BODY_TAG
2526  // the first couple of lines of RTF body so that after modification, then beginning can
2527  // once again be found
2528  LIST_COPY_EMAIL_STR("RTF Sync body tag", item->email->rtf_body_tag);
2529  break;
2530  case 0x1009: // PR_RTF_COMPRESSED - rtf data is lzw compressed
2531  LIST_COPY_EMAIL_BIN("RTF Compressed body", item->email->rtf_compressed);
2532  break;
2533  case 0x1010: // PR_RTF_SYNC_PREFIX_COUNT
2534  // a count of the ignored characters before the first significant character
2535  LIST_COPY_EMAIL_INT32("RTF whitespace prefix count", item->email->rtf_ws_prefix_count);
2536  break;
2537  case 0x1011: // PR_RTF_SYNC_TRAILING_COUNT
2538  // a count of the ignored characters after the last significant character
2539  LIST_COPY_EMAIL_INT32("RTF whitespace tailing count", item->email->rtf_ws_trailing_count);
2540  break;
2541  case 0x1013: // HTML body
2542  LIST_COPY_EMAIL_STR("HTML body", item->email->htmlbody);
2543  break;
2544  case 0x1035: // Message ID
2545  LIST_COPY_EMAIL_STR("Message ID", item->email->messageid);
2546  break;
2547  case 0x1042: // in-reply-to
2548  LIST_COPY_EMAIL_STR("In-Reply-To", item->email->in_reply_to);
2549  break;
2550  case 0x1046: // Return Path - this seems to be the message-id of the rfc822 mail that is being returned
2551  LIST_COPY_EMAIL_STR("Return Path", item->email->return_path_address);
2552  break;
2553  case 0x3001: // PR_DISPLAY_NAME File As
2554  LIST_COPY_STR("Display Name", item->file_as);
2555  break;
2556  case 0x3002: // PR_ADDRTYPE
2557  LIST_COPY_CONTACT_STR("Address Type", item->contact->address1_transport);
2558  break;
2559  case 0x3003: // PR_EMAIL_ADDRESS
2560  LIST_COPY_CONTACT_STR("Contact email Address", item->contact->address1);
2561  break;
2562  case 0x3004: // PR_COMMENT Comment for item - usually folders
2563  LIST_COPY_STR("Comment", item->comment);
2564  break;
2565  case 0x3007: // PR_CREATION_TIME Date 4 - Creation Date?
2566  LIST_COPY_TIME("Date 4 (Item Creation Date)", item->create_date);
2567  break;
2568  case 0x3008: // PR_LAST_MODIFICATION_TIME Date 5 - Modify Date
2569  LIST_COPY_TIME("Date 5 (Modify Date)", item->modify_date);
2570  break;
2571  case 0x300B: // PR_SEARCH_KEY Record Header 2
2572  LIST_COPY_EMAIL_STR("Record Search 2", item->email->outlook_search_key);
2573  break;
2574  case 0x35DF: // PR_VALID_FOLDER_MASK
2575  LIST_COPY_STORE_INT32("Valid Folder Mask", item->message_store->valid_mask);
2576  break;
2577  case 0x35E0: // PR_IPM_SUBTREE_ENTRYID Top of Personal Folder Record
2578  LIST_COPY_STORE_ENTRYID("Top of Personal Folder Record", item->message_store->top_of_personal_folder);
2579  break;
2580  case 0x35E2: // PR_IPM_OUTBOX_ENTRYID
2581  LIST_COPY_STORE_ENTRYID("Default Outbox Folder record", item->message_store->default_outbox_folder);
2582  break;
2583  case 0x35E3: // PR_IPM_WASTEBASKET_ENTRYID
2584  LIST_COPY_STORE_ENTRYID("Deleted Items Folder record", item->message_store->deleted_items_folder);
2585  break;
2586  case 0x35E4: // PR_IPM_SENTMAIL_ENTRYID
2587  LIST_COPY_STORE_ENTRYID("Sent Items Folder record", item->message_store->sent_items_folder);
2588  break;
2589  case 0x35E5: // PR_VIEWS_ENTRYID
2590  LIST_COPY_STORE_ENTRYID("User Views Folder record", item->message_store->user_views_folder);
2591  break;
2592  case 0x35E6: // PR_COMMON_VIEWS_ENTRYID
2593  LIST_COPY_STORE_ENTRYID("Common View Folder record", item->message_store->common_view_folder);
2594  break;
2595  case 0x35E7: // PR_FINDER_ENTRYID
2596  LIST_COPY_STORE_ENTRYID("Search Root Folder record", item->message_store->search_root_folder);
2597  break;
2598  case 0x3602: // PR_CONTENT_COUNT Number of emails stored in a folder
2599  LIST_COPY_FOLDER_INT32("Folder Email Count", item->folder->item_count);
2600  break;
2601  case 0x3603: // PR_CONTENT_UNREAD Number of unread emails
2602  LIST_COPY_FOLDER_INT32("Unread Email Count", item->folder->unseen_item_count);
2603  break;
2604  case 0x360A: // PR_SUBFOLDERS Has children
2605  MALLOC_FOLDER(item);
2606  LIST_COPY_BOOL("Has Subfolders", item->folder->subfolder);
2607  break;
2608  case 0x3613: // PR_CONTAINER_CLASS IPF.x
2609  LIST_COPY_CSTR(item->ascii_type);
2610  if (pst_strincmp("IPF.Note", item->ascii_type, 8) == 0)
2611  item->type = PST_TYPE_NOTE;
2612  else if (pst_strincmp("IPF.Imap", item->ascii_type, 8) == 0)
2613  item->type = PST_TYPE_NOTE;
2614  else if (pst_stricmp("IPF", item->ascii_type) == 0)
2615  item->type = PST_TYPE_NOTE;
2616  else if (pst_strincmp("IPF.Contact", item->ascii_type, 11) == 0)
2617  item->type = PST_TYPE_CONTACT;
2618  else if (pst_strincmp("IPF.Journal", item->ascii_type, 11) == 0)
2619  item->type = PST_TYPE_JOURNAL;
2620  else if (pst_strincmp("IPF.Appointment", item->ascii_type, 15) == 0)
2621  item->type = PST_TYPE_APPOINTMENT;
2622  else if (pst_strincmp("IPF.StickyNote", item->ascii_type, 14) == 0)
2623  item->type = PST_TYPE_STICKYNOTE;
2624  else if (pst_strincmp("IPF.Task", item->ascii_type, 8) == 0)
2625  item->type = PST_TYPE_TASK;
2626  else
2627  item->type = PST_TYPE_OTHER;
2628 
2629  DEBUG_INFO(("Container class %s [%"PRIi32"]\n", item->ascii_type, item->type));
2630  break;
2631  case 0x3617: // PR_ASSOC_CONTENT_COUNT
2632  // associated content are items that are attached to this folder
2633  // but are hidden from users
2634  LIST_COPY_FOLDER_INT32("Associated Content count", item->folder->assoc_count);
2635  break;
2636  case 0x3701: // PR_ATTACH_DATA_OBJ binary data of attachment
2637  DEBUG_INFO(("Binary Data [Size %i]\n", list->elements[x]->size));
2638  NULL_CHECK(attach);
2639  if (!list->elements[x]->data) { //special case
2640  attach->id2_val = list->elements[x]->type;
2641  DEBUG_INFO(("Seen a Reference. The data hasn't been loaded yet. [%#"PRIx64"]\n", attach->id2_val));
2642  } else {
2643  LIST_COPY_BIN(attach->data);
2644  }
2645  break;
2646  case 0x3704: // PR_ATTACH_FILENAME Attachment filename (8.3)
2647  NULL_CHECK(attach);
2648  LIST_COPY_STR("Attachment Filename", attach->filename1);
2649  break;
2650  case 0x3705: // PR_ATTACH_METHOD
2651  NULL_CHECK(attach);
2652  LIST_COPY_ENUM("Attachment method", attach->method, 0, 7,
2653  "No Attachment",
2654  "Attach By Value",
2655  "Attach By Reference",
2656  "Attach by Reference Resolve",
2657  "Attach by Reference Only",
2658  "Embedded Message",
2659  "OLE");
2660  break;
2661  case 0x3707: // PR_ATTACH_LONG_FILENAME Attachment filename (long?)
2662  NULL_CHECK(attach);
2663  LIST_COPY_STR("Attachment Filename long", attach->filename2);
2664  break;
2665  case 0x370B: // PR_RENDERING_POSITION
2666  // position in characters that the attachment appears in the plain text body
2667  NULL_CHECK(attach);
2668  LIST_COPY_INT32("Attachment Position", attach->position);
2669  break;
2670  case 0x370E: // PR_ATTACH_MIME_TAG Mime type of encoding
2671  NULL_CHECK(attach);
2672  LIST_COPY_STR("Attachment mime encoding", attach->mimetype);
2673  break;
2674  case 0x3710: // PR_ATTACH_MIME_SEQUENCE
2675  // sequence number for mime parts. Includes body
2676  NULL_CHECK(attach);
2677  LIST_COPY_INT32("Attachment Mime Sequence", attach->sequence);
2678  break;
2679  case 0x3712: // PR_ATTACH_CONTENT_ID
2680  // content identification header (Content-ID)
2681  NULL_CHECK(attach);
2682  LIST_COPY_STR("Content ID", attach->content_id);
2683  break;
2684  case 0x3A00: // PR_ACCOUNT
2685  LIST_COPY_CONTACT_STR("Contact's Account name", item->contact->account_name);
2686  break;
2687  case 0x3A01: // PR_ALTERNATE_RECIPIENT
2688  DEBUG_INFO(("Contact Alternate Recipient - NOT PROCESSED\n"));
2689  break;
2690  case 0x3A02: // PR_CALLBACK_TELEPHONE_NUMBER
2691  LIST_COPY_CONTACT_STR("Callback telephone number", item->contact->callback_phone);
2692  break;
2693  case 0x3A03: // PR_CONVERSION_PROHIBITED
2694  LIST_COPY_EMAIL_BOOL("Message Conversion Prohibited", item->email->conversion_prohibited);
2695  break;
2696  case 0x3A05: // PR_GENERATION suffix
2697  LIST_COPY_CONTACT_STR("Contacts Suffix", item->contact->suffix);
2698  break;
2699  case 0x3A06: // PR_GIVEN_NAME Contact's first name
2700  LIST_COPY_CONTACT_STR("Contacts First Name", item->contact->first_name);
2701  break;
2702  case 0x3A07: // PR_GOVERNMENT_ID_NUMBER
2703  LIST_COPY_CONTACT_STR("Contacts Government ID Number", item->contact->gov_id);
2704  break;
2705  case 0x3A08: // PR_BUSINESS_TELEPHONE_NUMBER
2706  LIST_COPY_CONTACT_STR("Business Telephone Number", item->contact->business_phone);
2707  break;
2708  case 0x3A09: // PR_HOME_TELEPHONE_NUMBER
2709  LIST_COPY_CONTACT_STR("Home Telephone Number", item->contact->home_phone);
2710  break;
2711  case 0x3A0A: // PR_INITIALS Contact's Initials
2712  LIST_COPY_CONTACT_STR("Contacts Initials", item->contact->initials);
2713  break;
2714  case 0x3A0B: // PR_KEYWORD
2715  LIST_COPY_CONTACT_STR("Keyword", item->contact->keyword);
2716  break;
2717  case 0x3A0C: // PR_LANGUAGE
2718  LIST_COPY_CONTACT_STR("Contact's Language", item->contact->language);
2719  break;
2720  case 0x3A0D: // PR_LOCATION
2721  LIST_COPY_CONTACT_STR("Contact's Location", item->contact->location);
2722  break;
2723  case 0x3A0E: // PR_MAIL_PERMISSION - Can the recipient receive and send email
2724  LIST_COPY_CONTACT_BOOL("Mail Permission", item->contact->mail_permission);
2725  break;
2726  case 0x3A0F: // PR_MHS_COMMON_NAME
2727  LIST_COPY_CONTACT_STR("MHS Common Name", item->contact->common_name);
2728  break;
2729  case 0x3A10: // PR_ORGANIZATIONAL_ID_NUMBER
2730  LIST_COPY_CONTACT_STR("Organizational ID #", item->contact->org_id);
2731  break;
2732  case 0x3A11: // PR_SURNAME Contact's Surname
2733  LIST_COPY_CONTACT_STR("Contacts Surname", item->contact->surname);
2734  break;
2735  case 0x3A12: // PR_ORIGINAL_ENTRY_ID
2736  DEBUG_INFO(("Original Entry ID - NOT PROCESSED\n"));
2737  break;
2738  case 0x3A13: // PR_ORIGINAL_DISPLAY_NAME
2739  DEBUG_INFO(("Original Display Name - NOT PROCESSED\n"));
2740  break;
2741  case 0x3A14: // PR_ORIGINAL_SEARCH_KEY
2742  DEBUG_INFO(("Original Search Key - NOT PROCESSED\n"));
2743  break;
2744  case 0x3A15: // PR_POSTAL_ADDRESS
2745  LIST_COPY_CONTACT_STR("Default Postal Address", item->contact->def_postal_address);
2746  break;
2747  case 0x3A16: // PR_COMPANY_NAME
2748  LIST_COPY_CONTACT_STR("Company Name", item->contact->company_name);
2749  break;
2750  case 0x3A17: // PR_TITLE - Job Title
2751  LIST_COPY_CONTACT_STR("Job Title", item->contact->job_title);
2752  break;
2753  case 0x3A18: // PR_DEPARTMENT_NAME
2754  LIST_COPY_CONTACT_STR("Department Name", item->contact->department);
2755  break;
2756  case 0x3A19: // PR_OFFICE_LOCATION
2757  LIST_COPY_CONTACT_STR("Office Location", item->contact->office_loc);
2758  break;
2759  case 0x3A1A: // PR_PRIMARY_TELEPHONE_NUMBER
2760  LIST_COPY_CONTACT_STR("Primary Telephone", item->contact->primary_phone);
2761  break;
2762  case 0x3A1B: // PR_BUSINESS2_TELEPHONE_NUMBER
2763  LIST_COPY_CONTACT_STR("Business Phone Number 2", item->contact->business_phone2);
2764  break;
2765  case 0x3A1C: // PR_MOBILE_TELEPHONE_NUMBER
2766  LIST_COPY_CONTACT_STR("Mobile Phone Number", item->contact->mobile_phone);
2767  break;
2768  case 0x3A1D: // PR_RADIO_TELEPHONE_NUMBER
2769  LIST_COPY_CONTACT_STR("Radio Phone Number", item->contact->radio_phone);
2770  break;
2771  case 0x3A1E: // PR_CAR_TELEPHONE_NUMBER
2772  LIST_COPY_CONTACT_STR("Car Phone Number", item->contact->car_phone);
2773  break;
2774  case 0x3A1F: // PR_OTHER_TELEPHONE_NUMBER
2775  LIST_COPY_CONTACT_STR("Other Phone Number", item->contact->other_phone);
2776  break;
2777  case 0x3A20: // PR_TRANSMITTABLE_DISPLAY_NAME
2778  LIST_COPY_CONTACT_STR("Transmittable Display Name", item->contact->transmittable_display_name);
2779  break;
2780  case 0x3A21: // PR_PAGER_TELEPHONE_NUMBER
2781  LIST_COPY_CONTACT_STR("Pager Phone Number", item->contact->pager_phone);
2782  break;
2783  case 0x3A22: // PR_USER_CERTIFICATE
2784  DEBUG_INFO(("User Certificate - NOT PROCESSED\n"));
2785  break;
2786  case 0x3A23: // PR_PRIMARY_FAX_NUMBER
2787  LIST_COPY_CONTACT_STR("Primary Fax Number", item->contact->primary_fax);
2788  break;
2789  case 0x3A24: // PR_BUSINESS_FAX_NUMBER
2790  LIST_COPY_CONTACT_STR("Business Fax Number", item->contact->business_fax);
2791  break;
2792  case 0x3A25: // PR_HOME_FAX_NUMBER
2793  LIST_COPY_CONTACT_STR("Home Fax Number", item->contact->home_fax);
2794  break;
2795  case 0x3A26: // PR_BUSINESS_ADDRESS_COUNTRY
2796  LIST_COPY_CONTACT_STR("Business Address Country", item->contact->business_country);
2797  break;
2798  case 0x3A27: // PR_BUSINESS_ADDRESS_CITY
2799  LIST_COPY_CONTACT_STR("Business Address City", item->contact->business_city);
2800  break;
2801  case 0x3A28: // PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE
2802  LIST_COPY_CONTACT_STR("Business Address State", item->contact->business_state);
2803  break;
2804  case 0x3A29: // PR_BUSINESS_ADDRESS_STREET
2805  LIST_COPY_CONTACT_STR("Business Address Street", item->contact->business_street);
2806  break;
2807  case 0x3A2A: // PR_BUSINESS_POSTAL_CODE
2808  LIST_COPY_CONTACT_STR("Business Postal Code", item->contact->business_postal_code);
2809  break;
2810  case 0x3A2B: // PR_BUSINESS_PO_BOX
2811  LIST_COPY_CONTACT_STR("Business PO Box", item->contact->business_po_box);
2812  break;
2813  case 0x3A2C: // PR_TELEX_NUMBER
2814  LIST_COPY_CONTACT_STR("Telex Number", item->contact->telex);
2815  break;
2816  case 0x3A2D: // PR_ISDN_NUMBER
2817  LIST_COPY_CONTACT_STR("ISDN Number", item->contact->isdn_phone);
2818  break;
2819  case 0x3A2E: // PR_ASSISTANT_TELEPHONE_NUMBER
2820  LIST_COPY_CONTACT_STR("Assistant Phone Number", item->contact->assistant_phone);
2821  break;
2822  case 0x3A2F: // PR_HOME2_TELEPHONE_NUMBER
2823  LIST_COPY_CONTACT_STR("Home Phone 2", item->contact->home_phone2);
2824  break;
2825  case 0x3A30: // PR_ASSISTANT
2826  LIST_COPY_CONTACT_STR("Assistant's Name", item->contact->assistant_name);
2827  break;
2828  case 0x3A40: // PR_SEND_RICH_INFO
2829  LIST_COPY_CONTACT_BOOL("Can receive Rich Text", item->contact->rich_text);
2830  break;
2831  case 0x3A41: // PR_WEDDING_ANNIVERSARY
2832  LIST_COPY_CONTACT_TIME("Wedding Anniversary", item->contact->wedding_anniversary);
2833  break;
2834  case 0x3A42: // PR_BIRTHDAY
2835  LIST_COPY_CONTACT_TIME("Birthday", item->contact->birthday);
2836  break;
2837  case 0x3A43: // PR_HOBBIES
2838  LIST_COPY_CONTACT_STR("Hobbies", item->contact->hobbies);
2839  break;
2840  case 0x3A44: // PR_MIDDLE_NAME
2841  LIST_COPY_CONTACT_STR("Middle Name", item->contact->middle_name);
2842  break;
2843  case 0x3A45: // PR_DISPLAY_NAME_PREFIX
2844  LIST_COPY_CONTACT_STR("Display Name Prefix (Title)", item->contact->display_name_prefix);
2845  break;
2846  case 0x3A46: // PR_PROFESSION
2847  LIST_COPY_CONTACT_STR("Profession", item->contact->profession);
2848  break;
2849  case 0x3A47: // PR_PREFERRED_BY_NAME
2850  LIST_COPY_CONTACT_STR("Preferred By Name", item->contact->pref_name);
2851  break;
2852  case 0x3A48: // PR_SPOUSE_NAME
2853  LIST_COPY_CONTACT_STR("Spouse's Name", item->contact->spouse_name);
2854  break;
2855  case 0x3A49: // PR_COMPUTER_NETWORK_NAME
2856  LIST_COPY_CONTACT_STR("Computer Network Name", item->contact->computer_name);
2857  break;
2858  case 0x3A4A: // PR_CUSTOMER_ID
2859  LIST_COPY_CONTACT_STR("Customer ID", item->contact->customer_id);
2860  break;
2861  case 0x3A4B: // PR_TTYTDD_PHONE_NUMBER
2862  LIST_COPY_CONTACT_STR("TTY/TDD Phone", item->contact->ttytdd_phone);
2863  break;
2864  case 0x3A4C: // PR_FTP_SITE
2865  LIST_COPY_CONTACT_STR("Ftp Site", item->contact->ftp_site);
2866  break;
2867  case 0x3A4D: // PR_GENDER
2868  LIST_COPY_CONTACT_ENUM16("Gender", item->contact->gender, 0, 3, "Unspecified", "Female", "Male");
2869  break;
2870  case 0x3A4E: // PR_MANAGER_NAME
2871  LIST_COPY_CONTACT_STR("Manager's Name", item->contact->manager_name);
2872  break;
2873  case 0x3A4F: // PR_NICKNAME
2874  LIST_COPY_CONTACT_STR("Nickname", item->contact->nickname);
2875  break;
2876  case 0x3A50: // PR_PERSONAL_HOME_PAGE
2877  LIST_COPY_CONTACT_STR("Personal Home Page", item->contact->personal_homepage);
2878  break;
2879  case 0x3A51: // PR_BUSINESS_HOME_PAGE
2880  LIST_COPY_CONTACT_STR("Business Home Page", item->contact->business_homepage);
2881  break;
2882  case 0x3A57: // PR_COMPANY_MAIN_PHONE_NUMBER
2883  LIST_COPY_CONTACT_STR("Company Main Phone", item->contact->company_main_phone);
2884  break;
2885  case 0x3A58: // PR_CHILDRENS_NAMES
2886  DEBUG_INFO(("Children's Names - NOT PROCESSED\n"));
2887  break;
2888  case 0x3A59: // PR_HOME_ADDRESS_CITY
2889  LIST_COPY_CONTACT_STR("Home Address City", item->contact->home_city);
2890  break;
2891  case 0x3A5A: // PR_HOME_ADDRESS_COUNTRY
2892  LIST_COPY_CONTACT_STR("Home Address Country", item->contact->home_country);
2893  break;
2894  case 0x3A5B: // PR_HOME_ADDRESS_POSTAL_CODE
2895  LIST_COPY_CONTACT_STR("Home Address Postal Code", item->contact->home_postal_code);
2896  break;
2897  case 0x3A5C: // PR_HOME_ADDRESS_STATE_OR_PROVINCE
2898  LIST_COPY_CONTACT_STR("Home Address State or Province", item->contact->home_state);
2899  break;
2900  case 0x3A5D: // PR_HOME_ADDRESS_STREET
2901  LIST_COPY_CONTACT_STR("Home Address Street", item->contact->home_street);
2902  break;
2903  case 0x3A5E: // PR_HOME_ADDRESS_POST_OFFICE_BOX
2904  LIST_COPY_CONTACT_STR("Home Address Post Office Box", item->contact->home_po_box);
2905  break;
2906  case 0x3A5F: // PR_OTHER_ADDRESS_CITY
2907  LIST_COPY_CONTACT_STR("Other Address City", item->contact->other_city);
2908  break;
2909  case 0x3A60: // PR_OTHER_ADDRESS_COUNTRY
2910  LIST_COPY_CONTACT_STR("Other Address Country", item->contact->other_country);
2911  break;
2912  case 0x3A61: // PR_OTHER_ADDRESS_POSTAL_CODE
2913  LIST_COPY_CONTACT_STR("Other Address Postal Code", item->contact->other_postal_code);
2914  break;
2915  case 0x3A62: // PR_OTHER_ADDRESS_STATE_OR_PROVINCE
2916  LIST_COPY_CONTACT_STR("Other Address State", item->contact->other_state);
2917  break;
2918  case 0x3A63: // PR_OTHER_ADDRESS_STREET
2919  LIST_COPY_CONTACT_STR("Other Address Street", item->contact->other_street);
2920  break;
2921  case 0x3A64: // PR_OTHER_ADDRESS_POST_OFFICE_BOX
2922  LIST_COPY_CONTACT_STR("Other Address Post Office box", item->contact->other_po_box);
2923  break;
2924  case 0x3FDE: // PR_INTERNET_CPID
2925  LIST_COPY_INT32("Internet code page", item->internet_cpid);
2926  break;
2927  case 0x3FFD: // PR_MESSAGE_CODEPAGE
2928  LIST_COPY_INT32("Message code page", item->message_codepage);
2929  break;
2930  case 0x65E3: // PR_PREDECESSOR_CHANGE_LIST
2932  DEBUG_INFO(("Predecessor Change\n"));
2934  break;
2935  case 0x67F2: // ID2 value of the attachment
2936  NULL_CHECK(attach);
2937  LIST_COPY_INT32("Attachment ID2 value", ut);
2938  attach->id2_val = ut;
2939  break;
2940  case 0x67FF: // Extra Property Identifier (Password CheckSum)
2941  LIST_COPY_STORE_INT32("Password checksum", item->message_store->pwd_chksum);
2942  break;
2943  case 0x6F02: // Secure HTML Body
2944  LIST_COPY_EMAIL_BIN("Secure HTML Body", item->email->encrypted_htmlbody);
2945  break;
2946  case 0x6F04: // Secure Text Body
2947  LIST_COPY_EMAIL_BIN("Secure Text Body", item->email->encrypted_body);
2948  break;
2949  case 0x7C07: // top of folders ENTRYID
2950  LIST_COPY_STORE_ENTRYID("Top of folders RecID", item->message_store->top_of_folder);
2951  break;
2952  case 0x8005: // Contact's Fullname
2953  LIST_COPY_CONTACT_STR("Contact Fullname", item->contact->fullname);
2954  break;
2955  case 0x801A: // Full Home Address
2956  LIST_COPY_CONTACT_STR("Home Address", item->contact->home_address);
2957  break;
2958  case 0x801B: // Full Business Address
2959  LIST_COPY_CONTACT_STR("Business Address", item->contact->business_address);
2960  break;
2961  case 0x801C: // Full Other Address
2962  LIST_COPY_CONTACT_STR("Other Address", item->contact->other_address);
2963  break;
2964  case 0x8045: // Work address street
2965  LIST_COPY_CONTACT_STR("Work address street", item->contact->work_address_street);
2966  break;
2967  case 0x8046: // Work address city
2968  LIST_COPY_CONTACT_STR("Work address city", item->contact->work_address_city);
2969  break;
2970  case 0x8047: // Work address state
2971  LIST_COPY_CONTACT_STR("Work address state", item->contact->work_address_state);
2972  break;
2973  case 0x8048: // Work address postalcode
2974  LIST_COPY_CONTACT_STR("Work address postalcode", item->contact->work_address_postalcode);
2975  break;
2976  case 0x8049: // Work address country
2977  LIST_COPY_CONTACT_STR("Work address country", item->contact->work_address_country);
2978  break;
2979  case 0x804A: // Work address postofficebox
2980  LIST_COPY_CONTACT_STR("Work address postofficebox", item->contact->work_address_postofficebox);
2981  break;
2982  case 0x8082: // Email Address 1 Transport
2983  LIST_COPY_CONTACT_STR("Email Address 1 Transport", item->contact->address1_transport);
2984  break;
2985  case 0x8083: // Email Address 1 Address
2986  LIST_COPY_CONTACT_STR("Email Address 1 Address", item->contact->address1);
2987  break;
2988  case 0x8084: // Email Address 1 Description
2989  LIST_COPY_CONTACT_STR("Email Address 1 Description", item->contact->address1_desc);
2990  break;
2991  case 0x8085: // Email Address 1 Record
2992  LIST_COPY_CONTACT_STR("Email Address 1 Record", item->contact->address1a);
2993  break;
2994  case 0x8092: // Email Address 2 Transport
2995  LIST_COPY_CONTACT_STR("Email Address 2 Transport", item->contact->address2_transport);
2996  break;
2997  case 0x8093: // Email Address 2 Address
2998  LIST_COPY_CONTACT_STR("Email Address 2 Address", item->contact->address2);
2999  break;
3000  case 0x8094: // Email Address 2 Description
3001  LIST_COPY_CONTACT_STR("Email Address 2 Description", item->contact->address2_desc);
3002  break;
3003  case 0x8095: // Email Address 2 Record
3004  LIST_COPY_CONTACT_STR("Email Address 2 Record", item->contact->address2a);
3005  break;
3006  case 0x80A2: // Email Address 3 Transport
3007  LIST_COPY_CONTACT_STR("Email Address 3 Transport", item->contact->address3_transport);
3008  break;
3009  case 0x80A3: // Email Address 3 Address
3010  LIST_COPY_CONTACT_STR("Email Address 3 Address", item->contact->address3);
3011  break;
3012  case 0x80A4: // Email Address 3 Description
3013  LIST_COPY_CONTACT_STR("Email Address 3 Description", item->contact->address3_desc);
3014  break;
3015  case 0x80A5: // Email Address 3 Record
3016  LIST_COPY_CONTACT_STR("Email Address 3 Record", item->contact->address3a);
3017  break;
3018  case 0x80D8: // Internet Free/Busy
3019  LIST_COPY_CONTACT_STR("Internet Free/Busy", item->contact->free_busy_address);
3020  break;
3021  case 0x8205: // PR_OUTLOOK_EVENT_SHOW_TIME_AS
3022  LIST_COPY_APPT_ENUM("Appointment shows as", item->appointment->showas, 0, 4,
3023  "Free", "Tentative", "Busy", "Out Of Office");
3024  break;
3025  case 0x8208: // PR_OUTLOOK_EVENT_LOCATION
3026  LIST_COPY_APPT_STR("Appointment Location", item->appointment->location);
3027  break;
3028  case 0x820d: // PR_OUTLOOK_EVENT_START_DATE
3029  LIST_COPY_APPT_TIME("Appointment Date Start", item->appointment->start);
3030  break;
3031  case 0x820e: // PR_OUTLOOK_EVENT_START_END
3032  LIST_COPY_APPT_TIME("Appointment Date End", item->appointment->end);
3033  break;
3034  case 0x8214: // Label for an appointment
3035  LIST_COPY_APPT_ENUM("Label for appointment", item->appointment->label, 0, 11,
3036  "None",
3037  "Important",
3038  "Business",
3039  "Personal",
3040  "Vacation",
3041  "Must Attend",
3042  "Travel Required",
3043  "Needs Preparation",
3044  "Birthday",
3045  "Anniversary",
3046  "Phone Call");
3047  break;
3048  case 0x8215: // PR_OUTLOOK_EVENT_ALL_DAY
3049  LIST_COPY_APPT_BOOL("All day flag", item->appointment->all_day);
3050  break;
3051  case 0x8216: // PR_OUTLOOK_EVENT_RECURRENCE_DATA
3052  LIST_COPY_APPT_BIN("Appointment recurrence data", item->appointment->recurrence_data);
3053  break;
3054  case 0x8223: // PR_OUTLOOK_EVENT_IS_RECURRING
3055  LIST_COPY_APPT_BOOL("Is recurring", item->appointment->is_recurring);
3056  break;
3057  case 0x8231: // Recurrence type
3058  LIST_COPY_APPT_ENUM("Appointment recurrence type ", item->appointment->recurrence_type, 0, 5,
3059  "None",
3060  "Daily",
3061  "Weekly",
3062  "Monthly",
3063  "Yearly");
3064  break;
3065  case 0x8232: // Recurrence description
3066  LIST_COPY_APPT_STR("Appointment recurrence description", item->appointment->recurrence_description);
3067  break;
3068  case 0x8234: // TimeZone as String
3069  LIST_COPY_APPT_STR("TimeZone of times", item->appointment->timezonestring);
3070  break;
3071  case 0x8235: // PR_OUTLOOK_EVENT_RECURRENCE_START
3072  LIST_COPY_APPT_TIME("Recurrence Start Date", item->appointment->recurrence_start);
3073  break;
3074  case 0x8236: // PR_OUTLOOK_EVENT_RECURRENCE_END
3075  LIST_COPY_APPT_TIME("Recurrence End Date", item->appointment->recurrence_end);
3076  break;
3077  case 0x8501: // PR_OUTLOOK_COMMON_REMINDER_MINUTES_BEFORE
3078  LIST_COPY_APPT_INT32("Alarm minutes", item->appointment->alarm_minutes);
3079  break;
3080  case 0x8503: // PR_OUTLOOK_COMMON_REMINDER_SET
3081  LIST_COPY_APPT_BOOL("Reminder alarm", item->appointment->alarm);
3082  break;
3083  case 0x8516: // Common start
3084  DEBUG_INFO(("Common Start Date - %s\n", pst_fileTimeToAscii((FILETIME*)list->elements[x]->data, time_buffer)));
3085  break;
3086  case 0x8517: // Common end
3087  DEBUG_INFO(("Common End Date - %s\n", pst_fileTimeToAscii((FILETIME*)list->elements[x]->data, time_buffer)));
3088  break;
3089  case 0x851f: // Play reminder sound filename
3090  LIST_COPY_APPT_STR("Appointment reminder sound filename", item->appointment->alarm_filename);
3091  break;
3092  case 0x8530: // Followup
3093  LIST_COPY_CONTACT_STR("Followup String", item->contact->followup);
3094  break;
3095  case 0x8534: // Mileage
3096  LIST_COPY_CONTACT_STR("Mileage", item->contact->mileage);
3097  break;
3098  case 0x8535: // Billing Information
3099  LIST_COPY_CONTACT_STR("Billing Information", item->contact->billing_information);
3100  break;
3101  case 0x8554: // PR_OUTLOOK_VERSION
3102  LIST_COPY_STR("Outlook Version", item->outlook_version);
3103  break;
3104  case 0x8560: // Appointment Reminder Time
3105  LIST_COPY_APPT_TIME("Appointment Reminder Time", item->appointment->reminder);
3106  break;
3107  case 0x8700: // Journal Type
3108  LIST_COPY_JOURNAL_STR("Journal Entry Type", item->journal->type);
3109  break;
3110  case 0x8706: // Journal Start date/time
3111  LIST_COPY_JOURNAL_TIME("Start Timestamp", item->journal->start);
3112  break;
3113  case 0x8708: // Journal End date/time
3114  LIST_COPY_JOURNAL_TIME("End Timestamp", item->journal->end);
3115  break;
3116  case 0x8712: // Journal Type Description
3117  LIST_COPY_JOURNAL_STR("Journal description", item->journal->description);
3118  break;
3119  default:
3120  if (list->elements[x]->type == (uint32_t)0x0002) {
3121  DEBUG_WARN(("Unknown type %#x 16bit int = %hi\n", list->elements[x]->mapi_id,
3122  *(int16_t*)list->elements[x]->data));
3123 
3124  } else if (list->elements[x]->type == (uint32_t)0x0003) {
3125  DEBUG_WARN(("Unknown type %#x 32bit int = %i\n", list->elements[x]->mapi_id,
3126  *(int32_t*)list->elements[x]->data));
3127 
3128  } else if (list->elements[x]->type == (uint32_t)0x0004) {
3129  DEBUG_WARN(("Unknown type %#x 4-byte floating [size = %#x]\n", list->elements[x]->mapi_id,
3130  list->elements[x]->size));
3131  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
3132 
3133  } else if (list->elements[x]->type == (uint32_t)0x0005) {
3134  DEBUG_WARN(("Unknown type %#x double floating [size = %#x]\n", list->elements[x]->mapi_id,
3135  list->elements[x]->size));
3136  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
3137 
3138  } else if (list->elements[x]->type == (uint32_t)0x0006) {
3139  DEBUG_WARN(("Unknown type %#x signed 64bit int = %"PRIi64"\n", list->elements[x]->mapi_id,
3140  *(int64_t*)list->elements[x]->data));
3141  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
3142 
3143  } else if (list->elements[x]->type == (uint32_t)0x0007) {
3144  DEBUG_WARN(("Unknown type %#x application time [size = %#x]\n", list->elements[x]->mapi_id,
3145  list->elements[x]->size));
3146  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
3147 
3148  } else if (list->elements[x]->type == (uint32_t)0x000a) {
3149  DEBUG_WARN(("Unknown type %#x 32bit error value = %i\n", list->elements[x]->mapi_id,
3150  *(int32_t*)list->elements[x]->data));
3151 
3152  } else if (list->elements[x]->type == (uint32_t)0x000b) {
3153  DEBUG_WARN(("Unknown type %#x 16bit boolean = %s [%hi]\n", list->elements[x]->mapi_id,
3154  (*((int16_t*)list->elements[x]->data)!=0?"True":"False"),
3155  *((int16_t*)list->elements[x]->data)));
3156 
3157  } else if (list->elements[x]->type == (uint32_t)0x000d) {
3158  DEBUG_WARN(("Unknown type %#x Embedded object [size = %#x]\n", list->elements[x]->mapi_id,
3159  list->elements[x]->size));
3160  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
3161 
3162  } else if (list->elements[x]->type == (uint32_t)0x0014) {
3163  DEBUG_WARN(("Unknown type %#x signed 64bit int = %"PRIi64"\n", list->elements[x]->mapi_id,
3164  *(int64_t*)list->elements[x]->data));
3165  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
3166 
3167  } else if (list->elements[x]->type == (uint32_t)0x001e) {
3168  DEBUG_WARN(("Unknown type %#x String Data = \"%s\"\n", list->elements[x]->mapi_id,
3169  list->elements[x]->data));
3170 
3171  } else if (list->elements[x]->type == (uint32_t)0x001f) {
3172  DEBUG_WARN(("Unknown type %#x Unicode String Data [size = %#x]\n", list->elements[x]->mapi_id,
3173  list->elements[x]->size));
3174  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
3175 
3176  } else if (list->elements[x]->type == (uint32_t)0x0040) {
3177  DEBUG_WARN(("Unknown type %#x Date = \"%s\"\n", list->elements[x]->mapi_id,
3178  pst_fileTimeToAscii((FILETIME*)list->elements[x]->data, time_buffer)));
3179 
3180  } else if (list->elements[x]->type == (uint32_t)0x0048) {
3181  DEBUG_WARN(("Unknown type %#x OLE GUID [size = %#x]\n", list->elements[x]->mapi_id,
3182  list->elements[x]->size));
3183  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
3184 
3185  } else if (list->elements[x]->type == (uint32_t)0x0102) {
3186  DEBUG_WARN(("Unknown type %#x Binary Data [size = %#x]\n", list->elements[x]->mapi_id,
3187  list->elements[x]->size));
3188  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
3189 
3190  } else if (list->elements[x]->type == (uint32_t)0x1003) {
3191  DEBUG_WARN(("Unknown type %#x Array of 32 bit values [size = %#x]\n", list->elements[x]->mapi_id,
3192  list->elements[x]->size));
3193  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
3194 
3195  } else if (list->elements[x]->type == (uint32_t)0x1014) {
3196  DEBUG_WARN(("Unknown type %#x Array of 64 bit values [siize = %#x]\n", list->elements[x]->mapi_id,
3197  list->elements[x]->size));
3198  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
3199 
3200  } else if (list->elements[x]->type == (uint32_t)0x101e) {
3201  DEBUG_WARN(("Unknown type %#x Array of Strings [size = %#x]\n", list->elements[x]->mapi_id,
3202  list->elements[x]->size));
3203  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
3204 
3205  } else if (list->elements[x]->type == (uint32_t)0x101f) {
3206  DEBUG_WARN(("Unknown type %#x Array of Unicode Strings [size = %#x]\n", list->elements[x]->mapi_id,
3207  list->elements[x]->size));
3208  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
3209 
3210  } else if (list->elements[x]->type == (uint32_t)0x1102) {
3211  DEBUG_WARN(("Unknown type %#x Array of binary data blobs [size = %#x]\n", list->elements[x]->mapi_id,
3212  list->elements[x]->size));
3213  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
3214 
3215  } else {
3216  DEBUG_WARN(("Unknown type %#x Not Printable [%#x]\n", list->elements[x]->mapi_id,
3217  list->elements[x]->type));
3218  DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
3219  }
3220 
3221  if (list->elements[x]->data) {
3222  free(list->elements[x]->data);
3223  list->elements[x]->data = NULL;
3224  }
3225  }
3226  }
3227  list = list->next;
3228  if (attach) attach = attach->next;
3229  }
3230  DEBUG_RET();
3231  return 0;
3232 }
3233 
3234 
3235 static void pst_free_list(pst_mapi_object *list) {
3236  pst_mapi_object *l;
3237  DEBUG_ENT("pst_free_list");
3238  while (list) {
3239  if (list->elements) {
3240  int32_t x;
3241  for (x=0; x < list->orig_count; x++) {
3242  if (list->elements[x]) {
3243  if (list->elements[x]->data) free(list->elements[x]->data);
3244  free(list->elements[x]);
3245  }
3246  }
3247  free(list->elements);
3248  }
3249  l = list->next;
3250  free (list);
3251  list = l;
3252  }
3253  DEBUG_RET();
3254 }
3255 
3256 
3257 static void pst_free_id2(pst_id2_tree * head) {
3258  pst_id2_tree *t;
3259  DEBUG_ENT("pst_free_id2");
3260  while (head) {
3261  pst_free_id2(head->child);
3262  t = head->next;
3263  free(head);
3264  head = t;
3265  }
3266  DEBUG_RET();
3267 }
3268 
3269 
3270 static void pst_free_desc (pst_desc_tree *head) {
3271  pst_desc_tree *t;
3272  DEBUG_ENT("pst_free_desc");
3273  while (head) {
3274  pst_free_desc(head->child);
3275  t = head->next;
3276  free(head);
3277  head = t;
3278  }
3279  DEBUG_RET();
3280 }
3281 
3282 
3284  pst_x_attrib_ll *t;
3285  DEBUG_ENT("pst_free_xattrib");
3286  while (x) {
3287  if (x->data) free(x->data);
3288  t = x->next;
3289  free(x);
3290  x = t;
3291  }
3292  DEBUG_RET();
3293 }
3294 
3295 
3297  pst_block_header block_head;
3298  pst_id2_tree *head = NULL, *tail = NULL;
3299  uint16_t x = 0;
3300  char *b_ptr = NULL;
3301  char *buf = NULL;
3302  pst_id2_assoc id2_rec;
3303  pst_index_ll *i_ptr = NULL;
3304  pst_id2_tree *i2_ptr = NULL;
3305  DEBUG_ENT("pst_build_id2");
3306 
3307  if (pst_read_block_size(pf, list->offset, list->size, list->inflated_size, &buf) < list->size) {
3308  //an error occurred in block read
3309  DEBUG_WARN(("block read error occurred. offset = %#"PRIx64", size = %#"PRIx64"\n", list->offset, list->size));
3310  if (buf) free(buf);
3311  DEBUG_RET();
3312  return NULL;
3313  }
3314  DEBUG_HEXDUMPC(buf, list->size, 16);
3315 
3316  memcpy(&block_head, buf, sizeof(block_head));
3317  LE16_CPU(block_head.type);
3318  LE16_CPU(block_head.count);
3319 
3320  if (block_head.type != (uint16_t)0x0002) { // some sort of constant?
3321  DEBUG_WARN(("Unknown constant [%#hx] at start of id2 values [offset %#"PRIx64"].\n", block_head.type, list->offset));
3322  if (buf) free(buf);
3323  DEBUG_RET();
3324  return NULL;
3325  }
3326 
3327  DEBUG_INFO(("ID %#"PRIx64" is likely to be a description record. Count is %i (offset %#"PRIx64")\n",
3328  list->i_id, block_head.count, list->offset));
3329  x = 0;
3330  b_ptr = buf + ((pf->do_read64) ? 0x08 : 0x04);
3331  while (x < block_head.count) {
3332  b_ptr += pst_decode_assoc(pf, &id2_rec, b_ptr);
3333  DEBUG_INFO(("id2 = %#x, id = %#"PRIx64", child id = %#"PRIx64"\n", id2_rec.id2, id2_rec.id, id2_rec.child_id));
3334  if ((i_ptr = pst_getID(pf, id2_rec.id)) == NULL) {
3335  DEBUG_WARN(("%#"PRIx64" - Not Found\n", id2_rec.id));
3336  } else {
3337  DEBUG_INFO(("%#"PRIx64" - Offset %#"PRIx64", u1 %#"PRIx64", Size %"PRIi64"(%#"PRIx64")\n",
3338  i_ptr->i_id, i_ptr->offset, i_ptr->u1, i_ptr->size, i_ptr->inflated_size));
3339  // add it to the tree
3340  i2_ptr = (pst_id2_tree*) pst_malloc(sizeof(pst_id2_tree));
3341  i2_ptr->id2 = id2_rec.id2;
3342  i2_ptr->id = i_ptr;
3343  i2_ptr->child = NULL;
3344  i2_ptr->next = NULL;
3345  if (!head) head = i2_ptr;
3346  if (tail) tail->next = i2_ptr;
3347  tail = i2_ptr;
3348  if (id2_rec.child_id) {
3349  if ((i_ptr = pst_getID(pf, id2_rec.child_id)) == NULL) {
3350  DEBUG_WARN(("child id [%#"PRIx64"] not found\n", id2_rec.child_id));
3351  }
3352  else {
3353  i2_ptr->child = pst_build_id2(pf, i_ptr);
3354  }
3355  }
3356  }
3357  x++;
3358  }
3359  if (buf) free (buf);
3360  DEBUG_RET();
3361  return head;
3362 }
3363 
3364 
3365 static void pst_free_attach(pst_item_attach *attach) {
3366  while (attach) {
3367  pst_item_attach *t;
3368  SAFE_FREE_STR(attach->filename1);
3369  SAFE_FREE_STR(attach->filename2);
3370  SAFE_FREE_STR(attach->mimetype);
3371  SAFE_FREE_STR(attach->content_id);
3372  SAFE_FREE_BIN(attach->data);
3373  pst_free_id2(attach->id2_head);
3374  t = attach->next;
3375  free(attach);
3376  attach = t;
3377  }
3378 }
3379 
3380 
3381 void pst_freeItem(pst_item *item) {
3383 
3384  DEBUG_ENT("pst_freeItem");
3385  if (item) {
3386  if (item->email) {
3387  SAFE_FREE(item->email->arrival_date);
3388  SAFE_FREE_STR(item->email->cc_address);
3393  SAFE_FREE_STR(item->email->header);
3394  SAFE_FREE_STR(item->email->htmlbody);
3396  SAFE_FREE_STR(item->email->messageid);
3411  SAFE_FREE_STR(item->email->reply_to);
3419  SAFE_FREE(item->email->sent_date);
3423  SAFE_FREE(item->email->report_time);
3429  free(item->email);
3430  }
3431  if (item->folder) {
3432  free(item->folder);
3433  }
3434  if (item->message_store) {
3443  free(item->message_store);
3444  }
3445  if (item->contact) {
3447  SAFE_FREE_STR(item->contact->address1);
3451  SAFE_FREE_STR(item->contact->address2);
3455  SAFE_FREE_STR(item->contact->address3);
3462  SAFE_FREE(item->contact->birthday);
3484  SAFE_FREE_STR(item->contact->followup);
3486  SAFE_FREE_STR(item->contact->ftp_site);
3487  SAFE_FREE_STR(item->contact->fullname);
3488  SAFE_FREE_STR(item->contact->gov_id);
3489  SAFE_FREE_STR(item->contact->hobbies);
3493  SAFE_FREE_STR(item->contact->home_fax);
3500  SAFE_FREE_STR(item->contact->initials);
3503  SAFE_FREE_STR(item->contact->keyword);
3504  SAFE_FREE_STR(item->contact->language);
3505  SAFE_FREE_STR(item->contact->location);
3508  SAFE_FREE_STR(item->contact->mileage);
3510  SAFE_FREE_STR(item->contact->nickname);
3513  SAFE_FREE_STR(item->contact->org_id);
3530  SAFE_FREE_STR(item->contact->suffix);
3531  SAFE_FREE_STR(item->contact->surname);
3532  SAFE_FREE_STR(item->contact->telex);
3542  free(item->contact);
3543  }
3544 
3545  pst_free_attach(item->attach);
3546 
3547  while (item->extra_fields) {
3549  SAFE_FREE(item->extra_fields->value);
3550  et = item->extra_fields->next;
3551  free(item->extra_fields);
3552  item->extra_fields = et;
3553  }
3554  if (item->journal) {
3555  SAFE_FREE(item->journal->start);
3556  SAFE_FREE(item->journal->end);
3557  SAFE_FREE_STR(item->journal->type);
3558  free(item->journal);
3559  }
3560  if (item->appointment) {
3561  SAFE_FREE(item->appointment->start);
3562  SAFE_FREE(item->appointment->end);
3564  SAFE_FREE(item->appointment->reminder);
3571  free(item->appointment);
3572  }
3573  SAFE_FREE(item->ascii_type);
3574  SAFE_FREE_STR(item->body_charset);
3575  SAFE_FREE_STR(item->body);
3576  SAFE_FREE_STR(item->subject);
3577  SAFE_FREE_STR(item->comment);
3578  SAFE_FREE(item->create_date);
3579  SAFE_FREE_STR(item->file_as);
3580  SAFE_FREE(item->modify_date);
3582  SAFE_FREE_BIN(item->record_key);
3584  free(item);
3585  }
3586  DEBUG_RET();
3587 }
3588 
3589 
3596 static int pst_getBlockOffsetPointer(pst_file *pf, pst_id2_tree *i2_head, pst_subblocks *subblocks, uint32_t offset, pst_block_offset_pointer *p) {
3597  size_t size;
3598  pst_block_offset block_offset;
3599  DEBUG_ENT("pst_getBlockOffsetPointer");
3600  if (p->needfree) free(p->from);
3601  p->from = NULL;
3602  p->to = NULL;
3603  p->needfree = 0;
3604  if (!offset) {
3605  // no data
3606  p->from = p->to = NULL;
3607  }
3608  else if ((offset & 0xf) == (uint32_t)0xf) {
3609  // external index reference
3610  DEBUG_WARN(("Found id2 %#x value. Will follow it\n", offset));
3611  size = pst_ff_getID2block(pf, offset, i2_head, &(p->from));
3612  if (size) {
3613  p->to = p->from + size;
3614  p->needfree = 1;
3615  }
3616  else {
3617  if (p->from) {
3618  DEBUG_WARN(("size zero but non-null pointer\n"));
3619  free(p->from);
3620  }
3621  p->from = p->to = NULL;
3622  }
3623  }
3624  else {
3625  DEBUG_WARN(("Found internal %#x value.\n", offset));
3626  // internal index reference
3627  size_t subindex = offset >> 16;
3628  if (pf->do_read64 == 2) {
3629  // Shift over 3 more bits for new flags.
3630  subindex = subindex >> 3;
3631  }
3632  size_t suboffset = offset & 0xffff;
3633  if (subindex < subblocks->subblock_count) {
3634  if (pst_getBlockOffset(subblocks->subs[subindex].buf,
3635  subblocks->subs[subindex].read_size,
3636  subblocks->subs[subindex].i_offset,
3637  suboffset, &block_offset)) {
3638  p->from = subblocks->subs[subindex].buf + block_offset.from;
3639  p->to = subblocks->subs[subindex].buf + block_offset.to;
3640  }
3641  }
3642  }
3643  DEBUG_RET();
3644  return (p->from) ? 0 : 1;
3645 }
3646 
3647 
3649 static int pst_getBlockOffset(char *buf, size_t read_size, uint32_t i_offset, uint32_t offset, pst_block_offset *p) {
3650  uint32_t low = offset & 0xf;
3651  uint32_t of1 = offset >> 4;
3652  DEBUG_ENT("pst_getBlockOffset");
3653  if (!p || !buf || !i_offset || low || (i_offset+2+of1+sizeof(*p) > read_size)) {
3654  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));
3655  DEBUG_RET();
3656  return 0;
3657  }
3658  memcpy(&(p->from), &(buf[(i_offset+2)+of1]), sizeof(p->from));
3659  memcpy(&(p->to), &(buf[(i_offset+2)+of1+sizeof(p->from)]), sizeof(p->to));
3660  LE16_CPU(p->from);
3661  LE16_CPU(p->to);
3662  DEBUG_WARN(("get block offset finds from=%i(%#x), to=%i(%#x)\n", p->from, p->from, p->to, p->to));
3663  if (p->from > p->to || p->to > read_size) {
3664  DEBUG_WARN(("get block offset bad range\n"));
3665  DEBUG_RET();
3666  return 0;
3667  }
3668  DEBUG_RET();
3669  return 1;
3670 }
3671 
3672 
3673 static int pst_getID_compare(const void *key, const void *entry) {
3674  uint64_t key_id = *(const uint64_t*)key;
3675  uint64_t entry_id = ((const pst_index_ll*)entry)->i_id;
3676  return (key_id > entry_id) - (key_id < entry_id);
3677 }
3678 
3679 
3681 pst_index_ll* pst_getID(pst_file* pf, uint64_t i_id) {
3682  pst_index_ll *ptr;
3683  DEBUG_ENT("pst_getID");
3684  if (i_id == 0) {
3685  DEBUG_RET();
3686  return NULL;
3687  }
3688 
3689  //if (i_id & 1) DEBUG_INFO(("have odd id bit %#"PRIx64"\n", i_id));
3690  //if (i_id & 2) DEBUG_INFO(("have two id bit %#"PRIx64"\n", i_id));
3691  i_id -= (i_id & 1);
3692 
3693  DEBUG_INFO(("Trying to find %#"PRIx64"\n", i_id));
3694  ptr = bsearch(&i_id, pf->i_table, pf->i_count, sizeof *pf->i_table, pst_getID_compare);
3695  if (ptr) {DEBUG_INFO(("Found Value %#"PRIx64"\n", i_id)); }
3696  else {DEBUG_INFO(("ERROR: Value %#"PRIx64" not found\n", i_id)); }
3697  DEBUG_RET();
3698  return ptr;
3699 }
3700 
3701 
3702 static pst_id2_tree *pst_getID2(pst_id2_tree *head, uint64_t id2) {
3703  // the id2 values are only unique among siblings.
3704  // we must not recurse into children
3705  // the caller must supply the correct parent
3706  DEBUG_ENT("pst_getID2");
3707  DEBUG_INFO(("looking for id2 = %#"PRIx64"\n", id2));
3708  pst_id2_tree *ptr = head;
3709  while (ptr) {
3710  if (ptr->id2 == id2) break;
3711  ptr = ptr->next;
3712  }
3713  if (ptr && ptr->id) {
3714  DEBUG_INFO(("Found value %#"PRIx64"\n", ptr->id->i_id));
3715  DEBUG_RET();
3716  return ptr;
3717  }
3718  DEBUG_INFO(("ERROR Not Found\n"));
3719  DEBUG_RET();
3720  return NULL;
3721 }
3722 
3723 
3732 static pst_desc_tree* pst_getDptr(pst_file *pf, uint64_t d_id) {
3733  pst_desc_tree *ptr = pf->d_head;
3734  DEBUG_ENT("pst_getDptr");
3735  while (ptr && (ptr->d_id != d_id)) {
3736  //DEBUG_INFO(("Looking for %#"PRIx64" at node %#"PRIx64" with parent %#"PRIx64"\n", id, ptr->d_id, ptr->parent_d_id));
3737  if (ptr->child) {
3738  ptr = ptr->child;
3739  continue;
3740  }
3741  while (!ptr->next && ptr->parent) {
3742  ptr = ptr->parent;
3743  }
3744  ptr = ptr->next;
3745  }
3746  DEBUG_RET();
3747  return ptr; // will be NULL or record we are looking for
3748 }
3749 
3750 
3751 static void pst_printDptr(pst_file *pf, pst_desc_tree *ptr) {
3752  DEBUG_ENT("pst_printDptr");
3753  while (ptr) {
3754  DEBUG_INFO(("%#"PRIx64" [%i] desc=%#"PRIx64", assoc tree=%#"PRIx64"\n", ptr->d_id, ptr->no_child,
3755  (ptr->desc ? ptr->desc->i_id : (uint64_t)0),
3756  (ptr->assoc_tree ? ptr->assoc_tree->i_id : (uint64_t)0)));
3757  if (ptr->child) {
3758  pst_printDptr(pf, ptr->child);
3759  }
3760  ptr = ptr->next;
3761  }
3762  DEBUG_RET();
3763 }
3764 
3765 
3766 static void pst_printID2ptr(pst_id2_tree *ptr) {
3767  DEBUG_ENT("pst_printID2ptr");
3768  while (ptr) {
3769  DEBUG_INFO(("%#"PRIx64" id=%#"PRIx64"\n", ptr->id2, (ptr->id ? ptr->id->i_id : (uint64_t)0)));
3770  if (ptr->child) pst_printID2ptr(ptr->child);
3771  ptr = ptr->next;
3772  }
3773  DEBUG_RET();
3774 }
3775 
3776 
3786 static size_t pst_read_raw_block_size(pst_file *pf, int64_t offset, size_t size, char **buf) {
3787  size_t rsize;
3788  DEBUG_ENT("pst_read_raw_block_size");
3789  DEBUG_INFO(("Reading raw block from %#"PRIx64", %x bytes\n", offset, size));
3790 
3791  if (*buf) {
3792  DEBUG_INFO(("Freeing old memory\n"));
3793  free(*buf);
3794  }
3795  *buf = (char*) pst_malloc(size);
3796 
3797  rsize = pst_getAtPos(pf, offset, *buf, size);
3798  if (rsize != size) {
3799  DEBUG_WARN(("Didn't read all the data. fread returned less [%i instead of %i]\n", rsize, size));
3800  if (feof(pf->fp)) {
3801  DEBUG_WARN(("We tried to read past the end of the file at [offset %#"PRIx64", size %#x]\n", offset, size));
3802  } else if (ferror(pf->fp)) {
3803  DEBUG_WARN(("Error is set on file stream.\n"));
3804  } else {
3805  DEBUG_WARN(("I can't tell why it failed\n"));
3806  }
3807  }
3808 
3809  DEBUG_RET();
3810  return rsize;
3811 }
3812 
3813 static size_t pst_read_block_size(pst_file *pf, int64_t offset, size_t size, size_t inflated_size, char **buf) {
3814  DEBUG_ENT("pst_read_block_size");
3815  DEBUG_INFO(("Reading block from %#"PRIx64", %x bytes, %x inflated\n", offset, size, inflated_size));
3816  if (inflated_size <= size) {
3817  // Not deflated.
3818  size_t ret = pst_read_raw_block_size(pf, offset, size, buf);
3819  DEBUG_RET();
3820  return ret;
3821  }
3822  // We need to read the raw block and inflate it.
3823  char *zbuf = NULL;
3824  if (pst_read_raw_block_size(pf, offset, size, &zbuf) != size) {
3825  DEBUG_WARN(("Failed to read %i bytes\n", size));
3826  if (zbuf) free(zbuf);
3827  DEBUG_RET();
3828  return -1;
3829  }
3830  *buf = (char *) pst_malloc(inflated_size);
3831  size_t result_size = inflated_size;
3832  if (uncompress((Bytef *) *buf, &result_size, (Bytef *) zbuf, size) != Z_OK || result_size != inflated_size) {
3833  DEBUG_WARN(("Failed to uncompress %i bytes to %i bytes, got %i\n", size, inflated_size, result_size));
3834  if (zbuf) free(zbuf);
3835  DEBUG_RET();
3836  return -1;
3837  }
3838  DEBUG_RET();
3839  return inflated_size;
3840 }
3841 
3842 
3843 
3854 static int pst_decrypt(uint64_t i_id, char *buf, size_t size, unsigned char type) {
3855  size_t x = 0;
3856  unsigned char y;
3857  DEBUG_ENT("pst_decrypt");
3858  if (!buf) {
3859  DEBUG_RET();
3860  return -1;
3861  }
3862 
3863  if (type == PST_COMP_ENCRYPT) {
3864  x = 0;
3865  while (x < size) {
3866  y = (unsigned char)(buf[x]);
3867  buf[x] = (char)comp_enc[y]; // transpose from encrypt array
3868  x++;
3869  }
3870 
3871  } else if (type == PST_ENCRYPT) {
3872  // The following code was based on the information at
3873  // http://www.passcape.com/outlook_passwords.htm
3874  uint16_t salt = (uint16_t) (((i_id & 0x00000000ffff0000) >> 16) ^ (i_id & 0x000000000000ffff));
3875  x = 0;
3876  while (x < size) {
3877  uint8_t losalt = (salt & 0x00ff);
3878  uint8_t hisalt = (salt & 0xff00) >> 8;
3879  y = (unsigned char)buf[x];
3880  y += losalt;
3881  y = comp_high1[y];
3882  y += hisalt;
3883  y = comp_high2[y];
3884  y -= hisalt;
3885  y = comp_enc[y];
3886  y -= losalt;
3887  buf[x] = (char)y;
3888  x++;
3889  salt++;
3890  }
3891 
3892  } else {
3893  DEBUG_WARN(("Unknown encryption: %i. Cannot decrypt\n", type));
3894  DEBUG_RET();
3895  return -1;
3896  }
3897  DEBUG_RET();
3898  return 0;
3899 }
3900 
3901 
3902 static uint64_t pst_getIntAt(pst_file *pf, char *buf) {
3903  uint64_t buf64;
3904  uint32_t buf32;
3905  if (pf->do_read64) {
3906  memcpy(&buf64, buf, sizeof(buf64));
3907  LE64_CPU(buf64);
3908  return buf64;
3909  }
3910  else {
3911  memcpy(&buf32, buf, sizeof(buf32));
3912  LE32_CPU(buf32);
3913  return buf32;
3914  }
3915 }
3916 
3917 
3918 static uint64_t pst_getIntAtPos(pst_file *pf, int64_t pos ) {
3919  uint64_t buf64;
3920  uint32_t buf32;
3921  if (pf->do_read64) {
3922  (void)pst_getAtPos(pf, pos, &buf64, sizeof(buf64));
3923  LE64_CPU(buf64);
3924  return buf64;
3925  }
3926  else {
3927  (void)pst_getAtPos(pf, pos, &buf32, sizeof(buf32));
3928  LE32_CPU(buf32);
3929  return buf32;
3930  }
3931 }
3932 
3942 static size_t pst_getAtPos(pst_file *pf, int64_t pos, void* buf, size_t size) {
3943  size_t rc;
3944  DEBUG_ENT("pst_getAtPos");
3945 // pst_block_recorder **t = &pf->block_head;
3946 // pst_block_recorder *p = pf->block_head;
3947 // while (p && ((p->offset+p->size) <= pos)) {
3948 // t = &p->next;
3949 // p = p->next;
3950 // }
3951 // if (p && (p->offset <= pos) && (pos < (p->offset+p->size))) {
3952 // // bump the count
3953 // p->readcount++;
3954 // } else {
3955 // // add a new block
3956 // pst_block_recorder *tail = *t;
3957 // p = (pst_block_recorder*)pst_malloc(sizeof(*p));
3958 // *t = p;
3959 // p->next = tail;
3960 // p->offset = pos;
3961 // p->size = size;
3962 // p->readcount = 1;
3963 // }
3964 // DEBUG_INFO(("pst file old offset %#"PRIx64" old size %#x read count %i offset %#"PRIx64" size %#x\n",
3965 // p->offset, p->size, p->readcount, pos, size));
3966 
3967  if (fseeko(pf->fp, pos, SEEK_SET) == -1) {
3968  DEBUG_RET();
3969  return 0;
3970  }
3971  rc = fread(buf, (size_t)1, size, pf->fp);
3972  DEBUG_RET();
3973  return rc;
3974 }
3975 
3976 
3985 size_t pst_ff_getIDblock_dec(pst_file *pf, uint64_t i_id, char **buf) {
3986  size_t r;
3987  int noenc = (int)(i_id & 2); // disable encryption
3988  DEBUG_ENT("pst_ff_getIDblock_dec");
3989  DEBUG_INFO(("for id %#"PRIx64"\n", i_id));
3990  r = pst_ff_getIDblock(pf, i_id, buf);
3991  if ((pf->encryption) && !(noenc)) {
3992  (void)pst_decrypt(i_id, *buf, r, pf->encryption);
3993  }
3994  DEBUG_HEXDUMPC(*buf, r, 16);
3995  DEBUG_RET();
3996  return r;
3997 }
3998 
3999 
4008 static size_t pst_ff_getIDblock(pst_file *pf, uint64_t i_id, char** buf) {
4009  pst_index_ll *rec;
4010  size_t rsize;
4011  DEBUG_ENT("pst_ff_getIDblock");
4012  rec = pst_getID(pf, i_id);
4013  if (!rec) {
4014  DEBUG_INFO(("Cannot find ID %#"PRIx64"\n", i_id));
4015  DEBUG_RET();
4016  return 0;
4017  }
4018  DEBUG_INFO(("id = %#"PRIx64", record size = %#x, offset = %#x\n", i_id, rec->size, rec->offset));
4019  rsize = pst_read_block_size(pf, rec->offset, rec->size, rec->inflated_size, buf);
4020  DEBUG_RET();
4021  return rsize;
4022 }
4023 
4024 
4025 static size_t pst_ff_getID2block(pst_file *pf, uint64_t id2, pst_id2_tree *id2_head, char** buf) {
4026  size_t ret;
4027  pst_id2_tree* ptr;
4028  pst_holder h = {buf, NULL, 0, 0, 0};
4029  DEBUG_ENT("pst_ff_getID2block");
4030  ptr = pst_getID2(id2_head, id2);
4031 
4032  if (!ptr) {
4033  DEBUG_WARN(("Cannot find id2 value %#"PRIx64"\n", id2));
4034  DEBUG_RET();
4035  return 0;
4036  }
4037  ret = pst_ff_getID2data(pf, ptr->id, &h);
4038  DEBUG_RET();
4039  return ret;
4040 }
4041 
4042 
4051 static size_t pst_ff_getID2data(pst_file *pf, pst_index_ll *ptr, pst_holder *h) {
4052  size_t ret;
4053  char *b = NULL;
4054  DEBUG_ENT("pst_ff_getID2data");
4055  if (!(ptr->i_id & 0x02)) {
4056  ret = pst_ff_getIDblock_dec(pf, ptr->i_id, &b);
4057  ret = pst_append_holder(h, (size_t)0, &b, ret);
4058  free(b);
4059  } else {
4060  // here we will assume it is an indirection block that points to others
4061  DEBUG_INFO(("Assuming it is a multi-block record because of it's id %#"PRIx64"\n", ptr->i_id));
4062  ret = pst_ff_compile_ID(pf, ptr->i_id, h, (size_t)0);
4063  }
4064  ret = pst_finish_cleanup_holder(h, ret);
4065  DEBUG_RET();
4066  return ret;
4067 }
4068 
4069 
4079 static size_t pst_ff_compile_ID(pst_file *pf, uint64_t i_id, pst_holder *h, size_t size) {
4080  size_t z, a;
4081  uint16_t count, y;
4082  char *buf3 = NULL;
4083  char *buf2 = NULL;
4084  char *b_ptr;
4085  pst_block_hdr block_hdr;
4086  pst_table3_rec table3_rec; //for type 3 (0x0101) blocks
4087 
4088  DEBUG_ENT("pst_ff_compile_ID");
4089  a = pst_ff_getIDblock(pf, i_id, &buf3);
4090  if (!a) {
4091  if (buf3) free(buf3);
4092  DEBUG_RET();
4093  return 0;
4094  }
4095  DEBUG_HEXDUMPC(buf3, a, 16);
4096  memcpy(&block_hdr, buf3, sizeof(block_hdr));
4097  LE16_CPU(block_hdr.index_offset);
4098  LE16_CPU(block_hdr.type);
4099  LE32_CPU(block_hdr.offset);
4100  DEBUG_INFO(("block header (index_offset=%#hx, type=%#hx, offset=%#x)\n", block_hdr.index_offset, block_hdr.type, block_hdr.offset));
4101 
4102  count = block_hdr.type;
4103  b_ptr = buf3 + 8;
4104 
4105  // For indirect lookups through a table of i_ids, just recurse back into this
4106  // function, letting it concatenate all the data together, and then return the
4107  // total size of the data.
4108  if (block_hdr.index_offset == (uint16_t)0x0201) { // Indirect lookup (depth 2).
4109  for (y=0; y<count; y++) {
4110  b_ptr += pst_decode_type3(pf, &table3_rec, b_ptr);
4111  size = pst_ff_compile_ID(pf, table3_rec.id, h, size);
4112  }
4113  free(buf3);
4114  DEBUG_RET();
4115  return size;
4116  }
4117 
4118  if (block_hdr.index_offset != (uint16_t)0x0101) { //type 3
4119  DEBUG_WARN(("WARNING: not a type 0x0101 buffer, Treating as normal buffer\n"));
4120  if (pf->encryption) (void)pst_decrypt(i_id, buf3, a, pf->encryption);
4121  size = pst_append_holder(h, size, &buf3, a);
4122  free(buf3);
4123  DEBUG_RET();
4124  return size;
4125  }
4126 
4127  for (y=0; y<count; y++) {
4128  b_ptr += pst_decode_type3(pf, &table3_rec, b_ptr);
4129  z = pst_ff_getIDblock_dec(pf, table3_rec.id, &buf2);
4130  if (!z) {
4131  DEBUG_WARN(("call to getIDblock returned zero %i\n", z));
4132  if (buf2) free(buf2);
4133  free(buf3);
4134  DEBUG_RET();
4135  return z;
4136  }
4137  size = pst_append_holder(h, size, &buf2, z);
4138  }
4139 
4140  free(buf3);
4141  if (buf2) free(buf2);
4142  DEBUG_RET();
4143  return size;
4144 }
4145 
4146 
4155 static size_t pst_append_holder(pst_holder *h, size_t size, char **buf, size_t z) {
4156  char *t;
4157  DEBUG_ENT("pst_append_holder");
4158 
4159  // raw append to a buffer
4160  if (h->buf) {
4161  *(h->buf) = pst_realloc(*(h->buf), size+z+1);
4162  DEBUG_INFO(("appending read data of size %i onto main buffer from pos %i\n", z, size));
4163  memcpy(*(h->buf)+size, *buf, z);
4164 
4165  // base64 encoding to a file
4166  } else if ((h->base64 == 1) && h->fp) {
4167  //
4168  if (h->base64_extra) {
4169  // include any bytes left over from the last encoding
4170  *buf = (char*)pst_realloc(*buf, z+h->base64_extra);
4171  memmove(*buf+h->base64_extra, *buf, z);
4172  memcpy(*buf, h->base64_extra_chars, h->base64_extra);
4173  z += h->base64_extra;
4174  }
4175 
4176  // find out how many bytes will be left over after this encoding and save them
4177  h->base64_extra = z % 3;
4178  if (h->base64_extra) {
4179  z -= h->base64_extra;
4180  memcpy(h->base64_extra_chars, *buf+z, h->base64_extra);
4181  }
4182 
4183  // encode this chunk
4185  if (t) {
4186  DEBUG_INFO(("writing %i bytes to file as base64 [%i]. Currently %i\n", z, strlen(t), size));
4187  (void)pst_fwrite(t, (size_t)1, strlen(t), h->fp);
4188  free(t); // caught by valgrind
4189  }
4190 
4191  // raw append to a file
4192  } else if (h->fp) {
4193  DEBUG_INFO(("writing %i bytes to file. Currently %i\n", z, size));
4194  (void)pst_fwrite(*buf, (size_t)1, z, h->fp);
4195 
4196  // null output
4197  } else {
4198  // h-> does not specify any output
4199  }
4200  DEBUG_RET();
4201  return size+z;
4202 }
4203 
4204 
4211 static size_t pst_finish_cleanup_holder(pst_holder *h, size_t size) {
4212  char *t;
4213  DEBUG_ENT("pst_finish_cleanup_holder");
4214  if ((h->base64 == 1) && h->fp && h->base64_extra) {
4215  // need to encode any bytes left over
4217  if (t) {
4218  (void)pst_fwrite(t, (size_t)1, strlen(t), h->fp);
4219  free(t); // caught by valgrind
4220  }
4221  size += h->base64_extra;
4222  }
4223  DEBUG_RET();
4224  return size;
4225 }
4226 
4227 
4231 int pst_stricmp(char *a, char *b) {
4232  while(*a != '\0' && *b != '\0' && toupper(*a)==toupper(*b)) {
4233  a++; b++;
4234  }
4235  if (toupper(*a) == toupper(*b))
4236  return 0;
4237  else if (toupper(*a) < toupper(*b))
4238  return -1;
4239  else
4240  return 1;
4241 }
4242 
4243 
4244 static int pst_strincmp(char *a, char *b, size_t x) {
4245  // compare up to x chars in string a and b case-insensitively
4246  // returns -1 if a < b, 0 if a==b, 1 if a > b
4247  size_t y = 0;
4248  while (*a != '\0' && *b != '\0' && y < x && toupper(*a)==toupper(*b)) {
4249  a++; b++; y++;
4250  }
4251  // if we have reached the end of either string, or a and b still match
4252  if (*a == '\0' || *b == '\0' || toupper(*a)==toupper(*b))
4253  return 0;
4254  else if (toupper(*a) < toupper(*b))
4255  return -1;
4256  else
4257  return 1;
4258 }
4259 
4260 
4261 size_t pst_fwrite(const void* ptr, size_t size, size_t nmemb, FILE *stream) {
4262  size_t r;
4263  if (ptr)
4264  r = fwrite(ptr, size, nmemb, stream);
4265  else {
4266  r = 0;
4267  DEBUG_ENT("pst_fwrite");
4268  DEBUG_WARN(("An attempt to write a NULL Pointer was made\n"));
4269  DEBUG_RET();
4270  }
4271  return r;
4272 }
4273 
4274 
4275 static char* pst_wide_to_single(char *wt, size_t size) {
4276  // returns the first byte of each wide char. the size is the number of bytes in source
4277  char *x, *y;
4278  DEBUG_ENT("pst_wide_to_single");
4279  x = pst_malloc((size/2)+1);
4280  y = x;
4281  while (size != 0 && *wt != '\0') {
4282  *y = *wt;
4283  wt+=2;
4284  size -= 2;
4285  y++;
4286  }
4287  *y = '\0';
4288  DEBUG_RET();
4289  return x;
4290 }
4291 
4292 
4293 char* pst_rfc2426_escape(char* str, char **buf, size_t* buflen) {
4294  //static char* buf = NULL;
4295  //static size_t buflen = 0;
4296  char *ret, *a, *b;
4297  size_t x = 0;
4298  int y, z;
4299  if (!str) return NULL;
4300  DEBUG_ENT("rfc2426_escape");
4301  // calculate space required to escape all the following characters
4302  y = pst_chr_count(str, ',')
4303  + pst_chr_count(str, '\\')
4304  + pst_chr_count(str, ';')
4305  + pst_chr_count(str, '\n');
4306  z = pst_chr_count(str, '\r');
4307  if (y == 0 && z == 0)
4308  // there isn't any extra space required
4309  ret = str;
4310  else {
4311  x = strlen(str) + y - z + 1; // don't forget room for the NUL
4312  if (x > *buflen) {
4313  *buf = (char*)pst_realloc(*buf, x);
4314  *buflen = x;
4315  }
4316  a = str;
4317  b = *buf;
4318  while (*a != '\0') {
4319  switch (*a) {
4320  case ',' :
4321  case '\\':
4322  case ';' :
4323  *(b++) = '\\';
4324  *b = *a;
4325  break;
4326  case '\n': // newlines are encoded as "\n"
4327  *(b++) = '\\';
4328  *b = 'n';
4329  break;
4330  case '\r': // skip cr
4331  b--;
4332  break;
4333  default:
4334  *b=*a;
4335  }
4336  b++;
4337  a++;
4338  }
4339  *b = '\0'; // NUL-terminate the string (buf)
4340  ret = *buf;
4341  }
4342  DEBUG_RET();
4343  return ret;
4344 }
4345 
4346 
4347 static int pst_chr_count(char *str, char x) {
4348  int r = 0;
4349  while (*str) {
4350  if (*str == x) r++;
4351  str++;
4352  }
4353  return r;
4354 }
4355 
4356 
4357 char* pst_rfc2425_datetime_format(const FILETIME* ft, int buflen, char* result) {
4358  struct tm stm;
4359  DEBUG_ENT("rfc2425_datetime_format");
4360  pst_fileTimeToStructTM(ft, &stm);
4361  if (strftime(result, buflen, "%Y-%m-%dT%H:%M:%SZ", &stm)==0) {
4362  DEBUG_INFO(("Problem occurred formatting date\n"));
4363  }
4364  DEBUG_RET();
4365  return result;
4366 }
4367 
4368 
4369 char* pst_rfc2445_datetime_format(const FILETIME* ft, int buflen, char* result) {
4370  struct tm stm;
4371  DEBUG_ENT("rfc2445_datetime_format");
4372  pst_fileTimeToStructTM(ft, &stm);
4373  if (strftime(result, buflen, "%Y%m%dT%H%M%SZ", &stm)==0) {
4374  DEBUG_INFO(("Problem occurred formatting date\n"));
4375  }
4376  DEBUG_RET();
4377  return result;
4378 }
4379 
4380 
4381 char* pst_rfc2445_datetime_format_now(int buflen, char* result) {
4382  struct tm stm;
4383  time_t t = time(NULL);
4384  DEBUG_ENT("rfc2445_datetime_format_now");
4385  gmtime_r(&t, &stm);
4386  if (strftime(result, buflen, "%Y%m%dT%H%M%SZ", &stm)==0) {
4387  DEBUG_INFO(("Problem occurred formatting date\n"));
4388  }
4389  DEBUG_RET();
4390  return result;
4391 }
4392 
4393 
4402 static const char* codepage(int cp, int buflen, char* result);
4403 static const char* codepage(int cp, int buflen, char* result) {
4404  switch (cp) {
4405  case 932 : return "iso-2022-jp";
4406  case 936 : return "gb2313";
4407  case 950 : return "big5";
4408  case 1200 : return "ucs-2le";
4409  case 1201 : return "ucs-2be";
4410  case 20127 : return "us-ascii";
4411  case 20269 : return "iso-6937";
4412  case 20865 : return "iso-8859-15";
4413  case 20866 : return "koi8-r";
4414  case 21866 : return "koi8-u";
4415  case 28591 : return "iso-8859-1";
4416  case 28592 : return "iso-8859-2";
4417  case 28595 : return "iso-8859-5";
4418  case 28596 : return "iso-8859-6";
4419  case 28597 : return "iso-8859-7";
4420  case 28598 : return "iso-8859-8";
4421  case 28599 : return "iso-8859-9";
4422  case 28600 : return "iso-8859-10";
4423  case 28601 : return "iso-8859-11";
4424  case 28602 : return "iso-8859-12";
4425  case 28603 : return "iso-8859-13";
4426  case 28604 : return "iso-8859-14";
4427  case 28605 : return "iso-8859-15";
4428  case 28606 : return "iso-8859-16";
4429  case 50220 : return "iso-2022-jp";
4430  case 50221 : return "csiso2022jp";
4431  case 51932 : return "euc-jp";
4432  case 51949 : return "euc-kr";
4433  case 65000 : return "utf-7";
4434  case 65001 : return "utf-8";
4435  default :
4436  snprintf(result, buflen, "windows-%d", cp);
4437  return result;
4438  }
4439  return NULL;
4440 }
4441 
4442 
4451 const char* pst_default_charset(pst_item *item, int buflen, char* result) {
4452  return (item->body_charset.str) ? item->body_charset.str :
4453  (item->message_codepage) ? codepage(item->message_codepage, buflen, result) :
4454  (item->internet_cpid) ? codepage(item->internet_cpid, buflen, result) :
4455  (item->pf && item->pf->charset) ? item->pf->charset :
4456  "iso-8859-1";
4457 }
4458 
4459 
4465  int needs = 0;
4466  const int8_t *x = (int8_t *)str->str;
4467  while (*x) {
4468  if (*x <= 32) needs++;
4469  x++;
4470  }
4471  int n = strlen(str->str) + 2*needs + 15;
4472  char *buffer = pst_malloc(n);
4473  strcpy(buffer, "utf-8''");
4474  x = (int8_t *)str->str;
4475  const uint8_t *y = (uint8_t *)str->str;
4476  uint8_t *z = (uint8_t *)buffer;
4477  z += strlen(buffer); // skip the utf8 prefix
4478  while (*y) {
4479  if (*x <= 32) {
4480  *(z++) = (uint8_t)'%';
4481  snprintf(z, 3, "%2x", *y);
4482  z += 2;
4483  }
4484  else {
4485  *(z++) = *y;
4486  }
4487  x++;
4488  y++;
4489  }
4490  *z = '\0';
4491  free(str->str);
4492  str->str = buffer;
4493 }
4494 
4495 
4502 void pst_rfc2047(pst_item *item, pst_string *str, int needs_quote) {
4503  int has_space = 0;
4504  int needs_coding = 0;
4505  pst_convert_utf8(item, str);
4506  const int8_t *x = (int8_t *)str->str;
4507  while (*x) {
4508  if (*x == 32) has_space = 1;
4509  if (*x < 32) needs_coding = 1;
4510  x++;
4511  }
4512  if (needs_coding) {
4513  char *enc = pst_base64_encode_single(str->str, strlen(str->str));
4514  free(str->str);
4515  int n = strlen(enc) + 20;
4516  str->str = pst_malloc(n);
4517  snprintf(str->str, n, "=?utf-8?B?%s?=", enc);
4518  free(enc);
4519  }
4520  else if (has_space && needs_quote) {
4521  int n = strlen(str->str) + 10;
4522  char *buffer = pst_malloc(n);
4523  snprintf(buffer, n, "\"%s\"", str->str);
4524  free(str->str);
4525  str->str = buffer;
4526  }
4527 }
4528 
4529 
4536  if (!str->str) return;
4537  pst_convert_utf8(item, str);
4538 }
4539 
4540 
4547  DEBUG_ENT("pst_convert_utf8");
4548  char buffer[30];
4549  if (str->is_utf8) {
4550  DEBUG_WARN(("Already utf8\n"));
4551  DEBUG_RET();
4552  return;
4553  }
4554  if (!str->str) {
4555  str->str = strdup("");
4556  DEBUG_WARN(("null to empty string\n"));
4557  DEBUG_RET();
4558  return;
4559  }
4560  const char *charset = pst_default_charset(item, sizeof(buffer), buffer);
4561  DEBUG_WARN(("default charset is %s\n", charset));
4562  if (!strcasecmp("utf-8", charset)) {
4563  DEBUG_RET();
4564  return;
4565  }
4566  pst_vbuf *newer = pst_vballoc(2);
4567  size_t rc = pst_vb_8bit2utf8(newer, str->str, strlen(str->str) + 1, charset);
4568  if (rc == (size_t)-1) {
4569  free(newer->b);
4570  DEBUG_WARN(("Failed to convert %s to utf-8 - %s\n", charset, str->str));
4571  }
4572  else {
4573  free(str->str);
4574  str->str = newer->b;
4575  str->is_utf8 = 1;
4576  }
4577  free(newer);
4578  DEBUG_RET();
4579 }
4580 
4581 
4587 {
4588  const int bias = 30 * 24 * 60; // minutes in 30 days
4589  int m[4] = {3,4,4,5};
4591  memset(r, 0, sizeof(pst_recurrence));
4592  size_t s = appt->recurrence_data.size;
4593  size_t i = 0;
4594  char* p = appt->recurrence_data.data;
4595  if (p) {
4596  if (i+4 <= s) { r->signature = PST_LE_GET_UINT32(p+i); i += 4; }
4597  if (i <= s) { r->type = PST_LE_GET_UINT8(p+i) - 0x0a; i += 2; }
4598  if (i+4 <= s) { r->sub_type = PST_LE_GET_UINT32(p+i); i += 4; }
4599  if (r->sub_type <= 3) {
4600  int n = m[r->sub_type]; // number of parms for this sub_type
4601  int j = 0;
4602  for (j=0; j<n; j++) {
4603  if (i+4 <= s) { *(&r->parm1 + j) = PST_LE_GET_UINT32(p+i); i += 4; }
4604  }
4605  }
4606  if (i <= s) { r->termination = PST_LE_GET_UINT8(p+i) - 0x21; i += 4; }
4607  if (i+4 <= s) { r->count = PST_LE_GET_UINT32(p+i); i += 4; }
4608  if (r->termination == 2) r->count = 0;
4609  switch (r->type) {
4610  case 0: // daily
4611  if (r->sub_type == 0) {
4612  // simple daily
4613  r->interval = r->parm2 / (24 * 60); // was minutes between recurrences
4614  }
4615  else {
4616  // daily every weekday, subset of weekly
4617  r->interval = 1;
4618  r->bydaymask = r->parm4;
4619  }
4620  break;
4621  case 1: // weekly
4622  r->interval = r->parm2;
4623  r->bydaymask = r->parm4;
4624  break;
4625  case 2: // monthly
4626  r->interval = r->parm2;
4627  if (r->sub_type == 2) {
4628  // monthly on day d
4629  r->dayofmonth = r->parm4;
4630  }
4631  else {
4632  // monthly on 2nd tuesday
4633  r->bydaymask = r->parm4;
4634  r->position = r->parm5;
4635  }
4636  break;
4637  case 3: // yearly
4638  r->interval = 1;
4639  r->monthofyear = ((r->parm1 + bias/2) / bias) + 1;
4640  if (r->sub_type == 2) {
4641  // yearly on day d of month m
4642  r->dayofmonth = r->parm4;
4643  }
4644  else {
4645  // yearly on 2nd tuesday of month m
4646  r->bydaymask = r->parm4;
4647  r->position = r->parm5;
4648  }
4649  break;
4650  default:
4651  break;
4652  }
4653  }
4654  return r;
4655 }
4656 
4657 
4662 {
4663  if (r) free(r);
4664 }
pst_string sender_address
mapi element 0x0065 PR_SENT_REPRESENTING_EMAIL_ADDRESS
Definition: libpst.h:299
#define PST_MAP_HEADER
Definition: libpst.h:49
uint64_t offset
Definition: libpst.c:162
#define INDEX_TYPE_OFFSET
Definition: libpst.c:28
#define PST_ATTRIB_HEADER
Definition: libpst.h:52
int32_t valid_mask
mapi element 0x35df, bit mask of folders in this message store
Definition: libpst.h:389
pst_string original_cc
mapi element 0x0073 PR_ORIGINAL_DISPLAY_CC
Definition: libpst.h:225
pst_entryid * sent_items_folder
mapi element 0x35e4
Definition: libpst.h:370
pst_string timezonestring
mapi element 0x8234
Definition: libpst.h:731
uint32_t bydaymask
bit mask of days of the week
Definition: libpst.h:697
pst_string outlook_received_name1
mapi element 0x0040 PR_RECEIVED_BY_NAME
Definition: libpst.h:331
pst_string other_postal_code
mapi element 0x3a61 PR_OTHER_ADDRESS_POSTAL_CODE
Definition: libpst.h:554
#define LIST_COPY_BOOL(label, targ)
Definition: libpst.c:1942
char ** buf
Definition: libpst.c:69
#define LIST_COPY_APPT_BIN(label, targ)
Definition: libpst.c:2154
pst_binary pst_attach_to_mem(pst_file *pf, pst_item_attach *attach)
Assemble the binary attachment into a single buffer.
Definition: libpst.c:576
pst_string suffix
mapi element 0x3a05 PR_GENERATION (Jr., Sr., III, etc)
Definition: libpst.h:580
pst_string followup
mapi element 0x8530
Definition: libpst.h:475
int32_t alarm_minutes
mapi element 0x8501 PR_OUTLOOK_COMMON_REMINDER_MINUTES_BEFORE
Definition: libpst.h:727
pst_string work_address_city
mapi element 0x8046
Definition: libpst.h:594
struct pst_mapi_element pst_mapi_element
pst_string home_address
mapi element 0x801a
Definition: libpst.h:492
unsigned char encryption
Definition: libpst.h:932
FILETIME * wedding_anniversary
mapi element 0x3a41 PR_WEDDING_ANNIVERSARY
Definition: libpst.h:590
pst_binary encrypted_htmlbody
mapi element 0x6f02
Definition: libpst.h:190
struct pst_id2_assoc32 pst_id2_assoc32
pst_item_appointment * appointment
calendar mapi elements
Definition: libpst.h:800
size_t base64_extra
Definition: libpst.c:73
#define PST_COMP_ENCRYPT
Definition: libpst.h:44
pst_string address2_transport
mapi element 0x8092
Definition: libpst.h:415
struct pst_holder pst_holder
pst_desc_tree * d_tail
Definition: libpst.h:907
FILETIME * modify_date
mapi element 0x3008 PR_LAST_MODIFICATION_TIME
Definition: libpst.h:855
pst_item_contact * contact
contact mapi elements
Definition: libpst.h:790
pst_string comment
mapi element 0x3004 PR_COMMENT
Definition: libpst.h:829
struct pst_id2_assoc pst_id2_assoc
int32_t importance
mapi element 0x0017 PR_IMPORTANCE
Definition: libpst.h:199
pst_string billing_information
mapi element 0x8535
Definition: libpst.h:429
int32_t flags
mapi element 0x0e07 PR_MESSAGE_FLAGS
Definition: libpst.h:825
pst_string subject
mapi element 0x0037 PR_SUBJECT
Definition: libpst.h:835
pst_vbuf * pst_vballoc(size_t len)
Definition: vbuf.c:130
uint16_t type
Definition: libpst.c:690
int32_t recurrence_type
mapi element 0x8231
Definition: libpst.h:765
static int pst_chr_count(char *str, char x)
Definition: libpst.c:4347
void pst_vbappend(pst_vbuf *vb, void *b, size_t len)
append len bytes of b to vb, resize if necessary
Definition: vbuf.c:190
uint32_t position
occurrence of day for 2nd Tuesday of month, in which case position is 2
Definition: libpst.h:703
static size_t pst_ff_compile_ID(pst_file *pf, uint64_t i_id, pst_holder *h, size_t size)
find the actual data from an indirection i_id and send it to the destination specified by the pst_hol...
Definition: libpst.c:4079
pst_string home_fax
mapi element 0x3a25 PR_HOME_FAX_NUMBER
Definition: libpst.h:498
uint32_t parm4
Definition: libpst.h:686
pst_string mobile_phone
mapi element 0x3a1c PR_MOBILE_TELEPHONE_NUMBER
Definition: libpst.h:534
static void add_descriptor_to_list(pst_desc_tree *node, pst_desc_tree **head, pst_desc_tree **tail)
add a pst descriptor node to a linked list of such nodes.
Definition: libpst.c:443
#define INDEX_TYPE32A
Definition: libpst.c:24
uint16_t inflated_size
Definition: libpst.c:153
int rich_text
mapi element 0x3a40 PR_SEND_RICH_INFO
Definition: libpst.h:576
pst_string car_phone
mapi element 0x3a1e PR_CAR_TELEPHONE_NUMBER
Definition: libpst.h:457
pst_string alarm_filename
mapi element 0x851f
Definition: libpst.h:729
struct pst_table3_rec pst_table3_rec
pst_string hobbies
mapi element 0x3a43 PR_HOBBIES
Definition: libpst.h:490
pst_binary record_key
mapi element 0x0ff9 PR_RECORD_KEY
Definition: libpst.h:845
uint32_t parent_d_id
Definition: libpst.c:113
#define LIST_COPY_CSTR(targ)
Definition: libpst.c:1928
int subfolder
mapi element 0x360a PR_SUBFOLDERS
Definition: libpst.h:356
pst_string header
mapi element 0x007d PR_TRANSPORT_MESSAGE_HEADERS
Definition: libpst.h:192
static unsigned char comp_high1[]
for "strong" encryption, this is the second rotor of an Enigma 3 rotor cipher.
Definition: libpst.c:230
#define LE32_CPU(x)
Definition: define.h:198
static pst_mapi_object * pst_parse_block(pst_file *pf, uint64_t block_id, pst_id2_tree *i2_head)
Process a low level descriptor block (0x0101, 0xbcec, 0x7cec) into a list of MAPI objects...
Definition: libpst.c:1440
#define LIST_COPY_TIME(label, targ)
Definition: libpst.c:2101
pst_string transmittable_display_name
mapi element 0x3a20 PR_TRANSMITTABLE_DISPLAY_NAME
Definition: libpst.h:586
pst_string work_address_postofficebox
mapi element 0x804a
Definition: libpst.h:602
uint32_t tree_id
Definition: libpst.c:112
uint32_t offset
Definition: libpst.c:119
struct pst_desc_tree * child_tail
Definition: libpst.h:136
#define LIST_COPY_EMAIL_BIN(label, targ)
Definition: libpst.c:2149
pst_string initials
mapi element 0x3a0a PR_INITIALS
Definition: libpst.h:512
#define DEBUG_WARN(x)
Definition: define.h:165
int32_t original_sensitivity
mapi element 0x002e PR_ORIGINAL_SENSITIVITY
Definition: libpst.h:221
static size_t pst_read_raw_block_size(pst_file *pf, int64_t offset, size_t size, char **buf)
Read a block of data from file into memory.
Definition: libpst.c:3786
FILETIME * create_date
mapi element 0x3007 PR_CREATION_TIME
Definition: libpst.h:853
int32_t rtf_ws_trailing_count
mapi element 0x1011 PR_RTF_SYNC_TRAILING_COUNT, a count of the ignored characters after the last sign...
Definition: libpst.h:295
static void pst_free_id2(pst_id2_tree *head)
Definition: libpst.c:3257
uint32_t parent_d_id
Definition: libpst.c:136
#define LIST_COPY_APPT_ENUM(label, targ, delta, count,...)
Definition: libpst.c:2034
pst_string home_city
mapi element 0x3a59 PR_HOME_ADDRESS_CITY
Definition: libpst.h:494
pst_string business_homepage
mapi element 0x3a51 PR_BUSINESS_HOME_PAGE
Definition: libpst.h:441
uint32_t parm1
must be contiguous, not an array to make Python interface easier
Definition: libpst.h:683
pst_string address2a
mapi element 0x8095
Definition: libpst.h:411
pst_string other_country
mapi element 0x3a60 PR_OTHER_ADDRESS_COUNTRY
Definition: libpst.h:548
size_t subblock_count
Definition: libpst.c:86
uint64_t index2_back
back pointer value in the first b-tree node in the descriptor tree
Definition: libpst.h:926
pst_binary conversation_index
mapi element 0x0071 PR_CONVERSATION_INDEX
Definition: libpst.h:174
int delete_after_submit
mapi element 0x0e01 PR_DELETE_AFTER_SUBMIT
Definition: libpst.h:182
pst_entryid * default_outbox_folder
mapi element 0x35e2
Definition: libpst.h:366
pst_string processed_subject
mapi element 0x0070 PR_CONVERSATION_TOPIC
Definition: libpst.h:247
uint16_t size
Definition: libpst.c:144
#define LIST_COPY_APPT_INT32(label, targ)
Definition: libpst.c:2004
uint32_t termination
type of termination of the recurrence
Definition: libpst.h:693
uint64_t id
Definition: libpst.c:194
uint64_t id2_val
only used if the attachment is by reference, in which case this is the id2 reference ...
Definition: libpst.h:620
struct pst_x_attrib pst_x_attrib
pst_string computer_name
mapi element 0x3a49 PR_COMPUTER_NETWORK_NAME
Definition: libpst.h:463
int32_t internet_cpid
mapi element 0x3fde PR_INTERNET_CPID
Definition: libpst.h:837
pst_recurrence * pst_convert_recurrence(pst_item_appointment *appt)
Decode raw recurrence data into a better structure.
Definition: libpst.c:4586
size_t pst_vb_utf16to8(pst_vbuf *dest, const char *inbuf, int iblen)
Definition: vbuf.c:213
struct pst_desc_tree * parent
Definition: libpst.h:134
pst_string telex
mapi element 0x3a2c PR_TELEX_NUMBER
Definition: libpst.h:584
pst_string address1_desc
mapi element 0x8084
Definition: libpst.h:405
void pst_rfc2047(pst_item *item, pst_string *str, int needs_quote)
Convert str to rfc2047 encoding of str, possibly enclosed in quotes if it contains spaces...
Definition: libpst.c:4502
uint64_t parent_d_id
Definition: libpst.h:128
#define SAFE_FREE_STR(x)
Definition: libpst.c:1910
int64_t u1
Definition: libpst.h:114
pst_string home_street
mapi element 0x3a5d PR_HOME_ADDRESS_STREET
Definition: libpst.h:510
int alarm
mapi element 0x8503 PR_OUTLOOK_COMMON_REMINDER_SET
Definition: libpst.h:723
#define LIST_COPY_CONTACT_ENUM16(label, targ, delta, count,...)
Definition: libpst.c:2049
pst_string business_state
mapi element 0x3a28 PR_BUSINESS_ADDRESS_STATE_OR_PROVINCE
Definition: libpst.h:451
char * ascii_type
mapi element 0x001a PR_MESSAGE_CLASS or 0x3613 PR_CONTAINER_CLASS
Definition: libpst.h:813
uint32_t child_id
Definition: libpst.c:175
int rtf_in_sync
mapi element 0x0e1f PR_RTF_IN_SYNC, True means that the rtf version is same as text body...
Definition: libpst.h:289
void pst_freeItem(pst_item *item)
Free the item returned by pst_parse_item().
Definition: libpst.c:3381
pst_string work_address_street
mapi element 0x8045
Definition: libpst.h:592
size_t dlen
Definition: vbuf.h:10
struct pst_x_attrib_ll * next
link to next item in the list
Definition: libpst.h:881
pst_string business_po_box
mapi element 0x3a2b PR_BUSINESS_PO_BOX
Definition: libpst.h:447
int pst_load_extended_attributes(pst_file *pf)
Try to load the extended attributes from the pst file.
Definition: libpst.c:698
pst_item_journal * journal
journal mapi elements
Definition: libpst.h:798
uint64_t offset
Definition: libpst.h:111
#define LIST_COPY_APPT_STR(label, targ)
Definition: libpst.c:2090
static uint64_t pst_getIntAtPos(pst_file *pf, int64_t pos)
Definition: libpst.c:3918
#define PST_TYPE_TASK
Definition: libpst.h:37
char * pst_rfc2426_escape(char *str, char **buf, size_t *buflen)
Add any necessary escape characters for rfc2426 vcard format.
Definition: libpst.c:4293
#define LEVEL_INDICATOR_OFFSET
Definition: libpst.c:850
void * pst_malloc(size_t size)
Definition: debug.c:169
pst_string other_street
mapi element 0x3a63 PR_OTHER_ADDRESS_STREET
Definition: libpst.h:558
pst_string company_main_phone
mapi element 0x3a57 PR_COMPANY_MAIN_PHONE_NUMBER
Definition: libpst.h:459
pst_string address1_transport
mapi element 0x3002 PR_ADDRTYPE, or 0x8082
Definition: libpst.h:407
uint64_t block_id
block id that can be used to generate uid
Definition: libpst.h:784
uint32_t map
key for the mapping
Definition: libpst.h:877
struct pst_index32 pst_index32
#define LE16_CPU(x)
Definition: define.h:203
int16_t gender
mapi element 0x3a4d PR_GENDER
Definition: libpst.h:486
pst_string address3_transport
mapi element 0x80a2
Definition: libpst.h:423
unsigned char ind_type
index type or file type
Definition: libpst.h:938
pst_entryid * user_views_folder
mapi element 0x35e5
Definition: libpst.h:372
Definition: vbuf.h:9
pst_string other_po_box
mapi element 0x3a64 PR_OTHER_ADDRESS_POST_OFFICE_BOX
Definition: libpst.h:552
pst_string primary_fax
mapi element 0x3a23 PR_PRIMARY_FAX_NUMBER
Definition: libpst.h:566
pst_string department
mapi element 0x3a18 PR_DEPARTMENT_NAME
Definition: libpst.h:469
#define LIST_COPY_JOURNAL_TIME(label, targ)
Definition: libpst.c:2131
pst_binary encrypted_body
mapi element 0x6f04
Definition: libpst.h:188
uint32_t mytype
Definition: libpst.h:875
#define LIST_COPY_STORE_INT32(label, targ)
Definition: libpst.c:2014
uint32_t desc_id
Definition: libpst.c:111
char base64_extra_chars[2]
Definition: libpst.c:74
int pst_close(pst_file *pf)
Close a pst file.
Definition: libpst.c:410
int32_t unseen_item_count
mapi element 0x3603 PR_CONTENT_UNREAD
Definition: libpst.h:347
pst_string recurrence_description
mapi element 0x8232 recurrence description
Definition: libpst.h:767
pst_string business_country
mapi element 0x3a26 PR_BUSINESS_ADDRESS_COUNTRY
Definition: libpst.h:437
uint32_t id
Definition: libpst.h:105
#define BACKLINK_OFFSET
Definition: libpst.c:851
#define LIST_COPY_EMAIL_ENTRYID(label, targ)
Definition: libpst.c:2061
uint64_t d_id
Definition: libpst.h:127
#define DESC_BLOCK_SIZE
Definition: libpst.c:848
#define LIST_COPY_EMAIL_STR(label, targ)
Definition: libpst.c:2080
pst_string surname
mapi element 0x3a11 PR_SURNAME
Definition: libpst.h:582
FILETIME * end
mapi element 0x8708
Definition: libpst.h:656
struct pst_item_extra_field * next
Definition: libpst.h:646
static size_t pst_ff_getID2data(pst_file *pf, pst_index_ll *ptr, pst_holder *h)
find the actual data from an i_id and send it to the destination specified by the pst_holder h...
Definition: libpst.c:4051
size_t size
Definition: libpst.h:154
int conversion_prohibited
mapi element 0x3a03 PR_CONVERSION_PROHIBITED
Definition: libpst.h:178
#define PST_TYPE_SCHEDULE
Definition: libpst.h:32
pst_string outlook_sender
mapi element 0x003b PR_SENT_REPRESENTING_SEARCH_KEY
Definition: libpst.h:235
FILETIME * recurrence_start
mapi element 0x8235 PR_OUTLOOK_EVENT_RECURRENCE_START
Definition: libpst.h:771
pst_string display_name_prefix
mapi element 0x3a45 PR_DISPLAY_NAME_PREFIX
Definition: libpst.h:471
uint32_t type
Definition: libpst.c:94
pst_string sender2_access
mapi element 0x0c1e PR_SENDER_ADDRTYPE
Definition: libpst.h:301
pst_string work_address_state
mapi element 0x8047
Definition: libpst.h:596
int16_t u0
Definition: libpst.c:154
int32_t showas
mapi element 0x8205 PR_OUTLOOK_EVENT_SHOW_TIME_AS
Definition: libpst.h:737
pst_string language
mapi element 0x3a0c PR_LANGUAGE
Definition: libpst.h:520
static void freeall(pst_subblocks *subs, pst_block_offset_pointer *p1, pst_block_offset_pointer *p2, pst_block_offset_pointer *p3, pst_block_offset_pointer *p4, pst_block_offset_pointer *p5, pst_block_offset_pointer *p6, pst_block_offset_pointer *p7)
Definition: libpst.c:1413
#define DEBUG_INFO(x)
Definition: define.h:166
pst_string company_name
mapi element 0x3a16 PR_COMPANY_NAME
Definition: libpst.h:461
static char * pst_wide_to_single(char *wt, size_t size)
Definition: libpst.c:4275
pst_string location
mapi element 0x3a0d PR_LOCATION
Definition: libpst.h:522
FILETIME * reminder
mapi element 0x8560
Definition: libpst.h:725
uint64_t d_id
Definition: libpst.c:133
size_t pst_vb_8bit2utf8(pst_vbuf *dest, const char *inbuf, int iblen, const char *charset)
Definition: vbuf.c:254
This contains the common mapi elements, and pointers to structures for each major mapi item type...
Definition: libpst.h:780
#define DEBUG_ENT(x)
Definition: define.h:171
static pst_id2_tree * pst_build_id2(pst_file *pf, pst_index_ll *list)
Definition: libpst.c:3296
#define SECOND_POINTER
Definition: libpst.c:47
int32_t method
mapi element 0x3705 PR_ATTACH_METHOD
Definition: libpst.h:633
pst_entryid * top_of_personal_folder
mapi element 0x35e0
Definition: libpst.h:364
int base64
Definition: libpst.c:71
int32_t u1
Definition: libpst.c:155
pst_string profession
mapi element 0x3a46 PR_PROFESSION
Definition: libpst.h:570
#define DEBUG_RET()
Definition: define.h:176
int private_member
mapi element 0x002b PR_RECIPIENT_REASSIGNMENT_PROHIBITED
Definition: libpst.h:859
This contains the attachment related mapi elements.
Definition: libpst.h:608
pst_string def_postal_address
mapi element 0x3a15 PR_POSTAL_ADDRESS
Definition: libpst.h:467
Linked list of extended attributes.
Definition: libpst.h:871
size_t pst_attach_to_file_base64(pst_file *pf, pst_item_attach *attach, FILE *fp)
Write a binary attachment base64 encoded to a file.
Definition: libpst.c:624
const char * pst_default_charset(pst_item *item, int buflen, char *result)
Get the default character set for this item.
Definition: libpst.c:4451
pst_string reply_to
mapi element 0x0050 PR_REPLY_RECIPIENT_NAMES
Definition: libpst.h:265
uint32_t sub_type
implies number of recurrence parameters
Definition: libpst.h:681
char * cwd
original cwd when the file was opened
Definition: libpst.h:898
#define SAFE_FREE(x)
Definition: libpst.c:1909
pst_string free_busy_address
mapi element 0x80d8
Definition: libpst.h:477
pst_string outlook_recipient_name
mapi element 0x0044 PR_RCVD_REPRESENTING_NAME
Definition: libpst.h:231
pst_binary data
mapi element 0x3701 PR_ATTACH_DATA_OBJ
Definition: libpst.h:618
a simple wrapper for binary blobs
Definition: libpst.h:153
pst_string ttytdd_phone
mapi element 0x3a4b PR_TTYTDD_PHONE_NUMBER
Definition: libpst.h:588
pst_string report_text
mapi element 0x1001 PR_REPORT_TEXT, delivery report dsn body
Definition: libpst.h:317
#define LE64_CPU(x)
Definition: define.h:189
pst_entryid * common_view_folder
mapi element 0x35e6
Definition: libpst.h:374
pst_string body_charset
derived from extra_fields["content-type"] if it contains a charset= subfield
Definition: libpst.h:831
uint16_t count
Definition: libpst.c:168
size_t size
Definition: libpst.c:95
pst_entryid * deleted_items_folder
mapi element 0x35e3
Definition: libpst.h:368
int message_cc_me
mapi element 0x0058 PR_MESSAGE_CC_ME, this user is listed explicitly in the CC address ...
Definition: libpst.h:205
#define DEBUG_HEXDUMP(x, s)
Definition: define.h:167
uint32_t u1
Definition: libpst.c:137
pst_string nickname
mapi element 0x3a4f PR_NICKNAME
Definition: libpst.h:536
#define PST_TYPE_REPORT
Definition: libpst.h:39
uint32_t id2
Definition: libpst.c:173
pst_string file_as
mapi element 0x3001 PR_DISPLAY_NAME
Definition: libpst.h:827
static size_t pst_decode_table(pst_file *pf, struct pst_table_ptr_struct *table, char *buf)
Definition: libpst.c:892
static void record_descriptor(pst_file *pf, pst_desc_tree *node)
add a pst descriptor node into the global tree.
Definition: libpst.c:467
pst_string assistant_phone
mapi element 0x3a2e PR_ASSISTANT_TELEPHONE_NUMBER
Definition: libpst.h:427
static void pst_free_xattrib(pst_x_attrib_ll *x)
Definition: libpst.c:3283
pst_string first_name
mapi element 0x3a06 PR_GIVEN_NAME
Definition: libpst.h:473
struct pst_block_offset_pointer pst_block_offset_pointer
pst_string messageid
mapi element 0x1035
Definition: libpst.h:215
int32_t rtf_body_char_count
mapi element 0x1007 PR_RTF_SYNC_BODY_COUNT, a count of the significant characters in the rtf body...
Definition: libpst.h:271
pst_string address2
mapi element 0x8093
Definition: libpst.h:409
static size_t pst_read_block_size(pst_file *pf, int64_t offset, size_t size, size_t inflated_size, char **buf)
Definition: libpst.c:3813
FILE * fp
Definition: libpst.c:70
uint16_t unknown2
Definition: libpst.c:182
pst_string outlook_sender_name2
mapi element 0x0c1a PR_SENDER_NAME
Definition: libpst.h:333
void pst_fileTimeToStructTM(const FILETIME *filetime, struct tm *result)
Convert a FILETIME to unix struct tm.
Definition: timeconv.c:17
pst_string outlook_search_key
mapi element 0x300b PR_SEARCH_KEY
Definition: libpst.h:337
uint32_t monthofyear
month of year for yearly recurrences
Definition: libpst.h:701
The string is either utf8 encoded, or it is in the code page specified by the containing mapi object...
Definition: libpst.h:144
static size_t pst_append_holder(pst_holder *h, size_t size, char **buf, size_t z)
append (buf,z) data to the output destination (h,size)
Definition: libpst.c:4155
pst_string business_fax
mapi element 0x3a24 PR_BUSINESS_FAX_NUMBER
Definition: libpst.h:439
size_t i_count
Definition: libpst.h:905
#define PST_LE_GET_INT32(p)
Definition: define.h:241
uint32_t type
Definition: libpst.h:674
int32_t ndr_reason_code
mapi element 0x0c04 PR_NDR_REASON_CODE
Definition: libpst.h:321
pst_string job_title
mapi element 0x3a17 PR_TITLE
Definition: libpst.h:516
pst_string recip2_address
mapi element 0x0078 PR_RCVD_REPRESENTING_EMAIL_ADDRESS
Definition: libpst.h:259
uint64_t i_id
Definition: libpst.h:110
int autoforward
mapi element 0x0002 PR_ALTERNATE_RECIPIENT_ALLOWED
Definition: libpst.h:168
struct pst_desc_tree * next
Definition: libpst.h:133
int32_t priority
mapi element 0x0026 PR_PRIORITY
Definition: libpst.h:245
static size_t pst_finish_cleanup_holder(pst_holder *h, size_t size)
finish cleanup for base64 encoding to a file with extra bytes left over
Definition: libpst.c:4211
pst_string recip_access
mapi element 0x0075 PR_RECEIVED_BY_ADDRTYPE
Definition: libpst.h:253
uint32_t id
Definition: libpst.c:118
static int pst_decrypt(uint64_t i_id, char *buf, size_t size, unsigned char type)
Decrypt a block of data from the pst file.
Definition: libpst.c:3854
pst_desc_tree * pst_getTopOfFolders(pst_file *pf, const pst_item *root)
Get the top of folders descriptor tree.
Definition: libpst.c:544
pst_string outlook_recipient2
mapi element 0x0052 PR_RCVD_REPRESENTING_SEARCH_KEY
Definition: libpst.h:233
struct pst_id2_tree * child
Definition: libpst.h:121
static void pst_free_desc(pst_desc_tree *head)
Definition: libpst.c:3270
pst_string mimetype
mapi element 0x370e PR_ATTACH_MIME_TAG
Definition: libpst.h:614
int32_t label
mapi element 0x8214
Definition: libpst.h:750
#define LIST_COPY_APPT_BOOL(label, targ)
Definition: libpst.c:1966
pst_binary predecessor_change
mapi element 0x65e3 PR_PREDECESSOR_CHANGE_LIST
Definition: libpst.h:847
struct pst_desc_tree * child
Definition: libpst.h:135
int pst_open(pst_file *pf, const char *name, const char *charset)
Open a pst file.
Definition: libpst.c:315
FILETIME * birthday
mapi element 0x3a42 PR_BIRTHDAY
Definition: libpst.h:431
#define LIST_COPY_EMAIL_TIME(label, targ)
Definition: libpst.c:2116
#define LIST_COPY_EMAIL_ENUM(label, targ, delta, count,...)
Definition: libpst.c:2029
pst_index_ll * pst_getID(pst_file *pf, uint64_t i_id)
Lookup the i_id in the index linked list, and return a pointer to the element.
Definition: libpst.c:3681
int base64_line_count
Definition: libpst.c:72
uint64_t tree_id
Definition: libpst.c:135
uint64_t inflated_size
Definition: libpst.h:113
uint16_t map
Definition: libpst.c:691
int mail_permission
mapi element 0x3a0e PR_MAIL_PERMISSION
Definition: libpst.h:526
uint64_t desc_id
Definition: libpst.c:134
char * pst_rfc2445_datetime_format_now(int buflen, char *result)
Convert the current time rfc2445 date/time format 19531015T231000Z.
Definition: libpst.c:4381
pst_string keyword
mapi element 0x3a0b PR_KEYWORD
Definition: libpst.h:518
static pst_desc_tree * pst_getDptr(pst_file *pf, uint64_t d_id)
find the id in the descriptor tree rooted at pf->d_head
Definition: libpst.c:3732
pst_string cc_address
mapi element 0x0e03 PR_DISPLAY_CC
Definition: libpst.h:170
void pst_rfc2231(pst_string *str)
Convert str to rfc2231 encoding of str.
Definition: libpst.c:4464
static int pst_getBlockOffset(char *buf, size_t read_size, uint32_t i_offset, uint32_t offset, pst_block_offset *p)
Definition: libpst.c:3649
#define NULL_CHECK(x)
Definition: libpst.c:2161
#define PST_LE_GET_UINT8(p)
Definition: define.h:255
#define LIST_COPY_STORE_ENTRYID(label, targ)
Definition: libpst.c:2066
#define PST_MAP_ATTRIB
Definition: libpst.h:48
#define PST_LE_GET_UINT16(p)
Definition: define.h:247
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)
Process the index2 b-tree from the pst file and create the pf->d_head tree from it.
Definition: libpst.c:1140
char * data
Definition: libpst.h:155
size_t i_offset
Definition: libpst.c:81
static int pst_getID_compare(const void *key, const void *entry)
Definition: libpst.c:3673
pst_index_ll * desc
Definition: libpst.h:129
pst_string ftp_site
mapi element 0x3a4c PR_FTP_SITE
Definition: libpst.h:479
#define ENC_TYPE
Definition: libpst.c:49
uint32_t signature
0x30043004
Definition: libpst.h:669
pst_string sentto_address
mapi element 0x0e04 PR_DISPLAY_TO
Definition: libpst.h:315
int32_t rtf_ws_prefix_count
mapi element 0x1010 PR_RTF_SYNC_PREFIX_COUNT, a count of the ignored characters before the first sign...
Definition: libpst.h:292
uint64_t index1
file offset of the first b-tree node in the index tree
Definition: libpst.h:920
FILETIME * sent_date
mapi element 0x0039 PR_CLIENT_SUBMIT_TIME
Definition: libpst.h:311
struct pst_mapi_object * next
Definition: libpst.c:105
pst_string other_phone
mapi element 0x3a1f PR_OTHER_TELEPHONE_NUMBER
Definition: libpst.h:550
int delivery_report
mapi element 0x0023 PR_ORIGINATOR_DELIVERY_REPORT_REQUESTED
Definition: libpst.h:186
pst_string filename1
mapi element 0x3704 PR_ATTACH_FILENAME
Definition: libpst.h:610
uint32_t dayofmonth
day of month for monthly and yearly recurrences
Definition: libpst.h:699
int32_t assoc_count
mapi element 0x3617 PR_ASSOC_CONTENT_COUNT Associated content are items that are attached to this fol...
Definition: libpst.h:351
pst_string body
mapi element 0x1000 PR_BODY
Definition: libpst.h:833
size_t pst_ff_getIDblock_dec(pst_file *pf, uint64_t i_id, char **buf)
Get an ID block from file using pst_ff_getIDblock() and decrypt if necessary.
Definition: libpst.c:3985
pst_item_message_store * message_store
message store mapi elements
Definition: libpst.h:794
pst_string business_phone2
mapi element 0x3a1b PR_BUSINESS2_TELEPHONE_NUMBER
Definition: libpst.h:445
#define MAX_COUNT_OFFSET
Definition: libpst.c:853
int32_t message_size
mapi element 0x0e08 PR_MESSAGE_SIZE
Definition: libpst.h:841
static size_t pst_decode_index(pst_file *pf, pst_index *index, char *buf)
Definition: libpst.c:921
pst_subblock * subs
Definition: libpst.c:87
FILETIME * end
mapi element 0x820e PR_OUTLOOK_EVENT_START_END
Definition: libpst.h:717
#define PST_TYPE_STICKYNOTE
Definition: libpst.h:36
#define DEBUG_HEXDUMPC(x, s, c)
Definition: define.h:168
static pst_id2_tree * pst_getID2(pst_id2_tree *ptr, uint64_t id)
Definition: libpst.c:3702
pst_string common_name
mapi element 0x3a0f PR_MHS_COMMON_NAME
Definition: libpst.h:540
int32_t no_child
Definition: libpst.h:131
int32_t count_elements
Definition: libpst.c:101
static void pst_printDptr(pst_file *pf, pst_desc_tree *ptr)
Definition: libpst.c:3751
#define LIST_COPY_APPT_TIME(label, targ)
Definition: libpst.c:2126
uint32_t interval
recurrence interval in terms of the recurrence type
Definition: libpst.h:695
void pst_free_recurrence(pst_recurrence *r)
Free a recurrence structure.
Definition: libpst.c:4661
pst_string customer_id
mapi element 0x3a4a PR_CUSTOMER_ID
Definition: libpst.h:465
pst_entryid * top_of_folder
mapi element 0x7c07
Definition: libpst.h:378
#define INDEX_TYPE64A
Definition: libpst.c:26
pst_string manager_name
mapi element 0x3a4e PR_MANAGER_NAME
Definition: libpst.h:528
char * b
Definition: vbuf.h:13
int32_t count_objects
Definition: libpst.c:103
pst_string type
mapi element 0x8700
Definition: libpst.h:658
uint16_t unknown1
Definition: libpst.c:181
char * pst_base64_encode(void *data, size_t size)
Definition: libstrfunc.c:21
static size_t pst_decode_assoc(pst_file *pf, pst_id2_assoc *assoc, char *buf)
Definition: libpst.c:973
pst_string supplementary_info
mapi element 0x0c1b PR_SUPPLEMENTARY_INFO
Definition: libpst.h:325
pst_string org_id
mapi element 0x3a10 PR_ORGANIZATIONAL_ID_NUMBER
Definition: libpst.h:542
uint32_t extended
Definition: libpst.c:689
pst_string business_address
mapi element 0x801b
Definition: libpst.h:433
FILETIME * arrival_date
mapi element 0x0e06 PR_MESSAGE_DELIVERY_TIME
Definition: libpst.h:163
uint64_t offset
Definition: libpst.c:151
#define WARN(x)
Definition: define.h:152
uint32_t mapi_id
Definition: libpst.c:92
pst_string sender_access
mapi element 0x0064 PR_SENT_REPRESENTING_ADDRTYPE
Definition: libpst.h:297
pst_string outlook_recipient
mapi element 0x0051 PR_RECEIVED_BY_SEARCH_KEY
Definition: libpst.h:229
struct pst_subblocks pst_subblocks
uint16_t index_offset
Definition: libpst.c:199
pst_string assistant_name
mapi element 0x3a30 PR_ASSISTANT
Definition: libpst.h:425
int32_t message_codepage
mapi element 0x3ffd PR_MESSAGE_CODEPAGE
Definition: libpst.h:839
size_t i_capacity
Definition: libpst.h:905
int read_receipt
mapi element 0x0029 PR_READ_RECEIPT_REQUESTED
Definition: libpst.h:251
char * buf
Definition: libpst.c:79
pst_string callback_phone
mapi element 0x3a02 PR_CALLBACK_TELEPHONE_NUMBER
Definition: libpst.h:455
int32_t u1
Definition: libpst.c:146
uint16_t size
Definition: libpst.c:120
uint64_t i_id
calculated from id2_val during creation of record
Definition: libpst.h:622
pst_string bcc_address
mapi element 0x0e02 PR_DISPLAY_BCC
Definition: libpst.h:172
void * data
data target of the mapping, either uint32_t or string
Definition: libpst.h:879
pst_string address3
mapi element 0x80a3
Definition: libpst.h:417
uint32_t id
Definition: libpst.c:189
void pst_vbset(pst_vbuf *vb, void *b, size_t len)
set vbuf b size=len, resize if necessary, relen = how much to over-allocate
Definition: vbuf.c:180
pst_string outlook_version
mapi element 0x8554 PR_OUTLOOK_VERSION
Definition: libpst.h:843
uint64_t index2
file offset of the first b-tree node in the descriptor tree
Definition: libpst.h:924
#define LIST_COPY_JOURNAL_STR(label, targ)
Definition: libpst.c:2095
uint32_t offset
Definition: libpst.c:201
#define read_twobyte(BUF, OFF)
Definition: libpst.c:855
pst_x_attrib_ll * x_head
the head of the extended attributes linked list
Definition: libpst.h:909
pst_string home_po_box
mapi element 0x3a5e PR_HOME_ADDRESS_POST_OFFICE_BOX
Definition: libpst.h:504
pst_index_ll * assoc_tree
Definition: libpst.h:130
static int pst_getBlockOffsetPointer(pst_file *pf, pst_id2_tree *i2_head, pst_subblocks *subblocks, uint32_t offset, pst_block_offset_pointer *p)
The offset might be zero, in which case we have no data, so return a pair of null pointers...
Definition: libpst.c:3596
#define MALLOC_FOLDER(x)
Definition: libpst.c:1915
#define LIST_COPY_FOLDER_INT32(label, targ)
Definition: libpst.c:2009
int is_recurring
mapi element 0x8223 PR_OUTLOOK_EVENT_IS_RECURRING
Definition: libpst.h:758
pst_string htmlbody
mapi element 0x1013
Definition: libpst.h:194
#define BLOCK_SIZE
Definition: libpst.c:847
char * fname
original file name when the file was opened
Definition: libpst.h:900
int type
derived from mapi elements 0x001a PR_MESSAGE_CLASS or 0x3613 PR_CONTAINER_CLASS
Definition: libpst.h:811
uint16_t type
Definition: libpst.c:200
int32_t pwd_chksum
mapi element 0x76ff
Definition: libpst.h:391
#define LIST_COPY_CONTACT_TIME(label, targ)
Definition: libpst.c:2121
int32_t sequence
mapi element 0x3710 PR_ATTACH_MIME_SEQUENCE
Definition: libpst.h:637
static int pst_process(uint64_t block_id, pst_mapi_object *list, pst_item *item, pst_item_attach *attach)
process the list of MAPI objects produced from parse_block()
Definition: libpst.c:2179
int pst_reopen(pst_file *pf)
Reopen the pst file after a fork.
Definition: libpst.c:395
int message_to_me
mapi element 0x0057 PR_MESSAGE_TO_ME, this user is listed explicitly in the TO address ...
Definition: libpst.h:213
char * pst_rfc2425_datetime_format(const FILETIME *ft, int buflen, char *result)
Convert a FILETIME into rfc2425 date/time format 1953-10-15T23:10:00Z which is the same as one of the...
Definition: libpst.c:4357
uint16_t type
Definition: libpst.c:167
uint32_t parm5
Definition: libpst.h:687
#define INDEX_TYPE32
Definition: libpst.c:23
#define PST_FLAG_HAS_ATTACHMENT
Definition: libpst.h:94
pst_string radio_phone
mapi element 0x3a1d PR_RADIO_TELEPHONE_NUMBER
Definition: libpst.h:572
This contains the appointment related mapi elements.
Definition: libpst.h:713
pst_item_extra_field * extra_fields
linked list of extra headers and such
Definition: libpst.h:796
#define LIST_COPY_EMAIL_BOOL(label, targ)
Definition: libpst.c:1956
struct pst_desc pst_desc
int reply_requested
mapi element 0x0c17 PR_REPLY_REQUESTED
Definition: libpst.h:263
static size_t pst_decode_type3(pst_file *pf, pst_table3_rec *table3_rec, char *buf)
Definition: libpst.c:1001
pst_string home_country
mapi element 0x3a5a PR_HOME_ADDRESS_COUNTRY
Definition: libpst.h:496
pst_string address2_desc
mapi element 0x8094
Definition: libpst.h:413
static char * pst_getcwd(void)
Definition: libpst.c:303
#define SECOND_BACK
Definition: libpst.c:48
pst_string home_phone
mapi element 0x3a09 PR_HOME_TELEPHONE_NUMBER
Definition: libpst.h:500
static unsigned char comp_high2[]
for "strong" encryption, this is the third rotor of an Enigma 3 rotor cipher.
Definition: libpst.c:251
linked list of extra header fields
Definition: libpst.h:643
char * pst_fileTimeToAscii(const FILETIME *filetime, char *result)
Convert a FILETIME to ascii printable local time.
Definition: timeconv.c:5
static void pst_free_attach(pst_item_attach *attach)
Definition: libpst.c:3365
static size_t pst_decode_desc(pst_file *pf, pst_desc *desc, char *buf)
Definition: libpst.c:858
pst_entryid * search_root_folder
mapi element 0x35e7
Definition: libpst.h:376
uint16_t size
Definition: libpst.c:152
static void pst_free_list(pst_mapi_object *list)
Definition: libpst.c:3235
pst_string in_reply_to
mapi element 0x1042
Definition: libpst.h:201
uint64_t id
Definition: libpst.c:150
pst_string outlook_normalized_subject
mapi element 0x0e1d PR_NORMALIZED_SUBJECT
Definition: libpst.h:335
uint64_t index1_back
back pointer value in the first b-tree node in the index tree
Definition: libpst.h:922
int16_t u1
Definition: libpst.c:121
pst_binary recurrence_data
mapi element 0x8216 recurrence data
Definition: libpst.h:769
pst_string outlook_sender_name
mapi element 0x0042 PR_SENT_REPRESENTING_NAME
Definition: libpst.h:237
pst_string home_postal_code
mapi element 0x3a5b PR_HOME_ADDRESS_POSTAL_CODE
Definition: libpst.h:506
int is_utf8
Definition: libpst.h:147
uint64_t size
size of the pst file
Definition: libpst.h:928
int32_t orig_count
Definition: libpst.c:102
#define LIST_COPY_STR(label, targ)
Definition: libpst.c:2074
struct pst_block_hdr pst_block_hdr
pst_string sender2_address
mapi element 0x0c1f PR_SENDER_EMAIL_ADDRESS
Definition: libpst.h:303
uint64_t start
Definition: libpst.c:160
pst_binary rtf_compressed
mapi element 0x1009 PR_RTF_COMPRESSED, the compressed rtf body data.
Definition: libpst.h:281
char * pst_base64_encode_single(void *data, size_t size)
Definition: libstrfunc.c:28
uint64_t offset
Definition: libpst.c:143
uint32_t id
Definition: libpst.c:174
#define PST_TYPE_NOTE
Definition: libpst.h:31
pst_item * pst_parse_item(pst_file *pf, pst_desc_tree *d_ptr, pst_id2_tree *m_head)
Process a high level object from the pst file.
Definition: libpst.c:1249
pst_string home_state
mapi element 0x3a5c PR_HOME_ADDRESS_STATE_OR_PROVINCE
Definition: libpst.h:508
int32_t ndr_status_code
mapi element 0x0c20 PR_NDR_STATUS_CODE
Definition: libpst.h:327
#define LIST_COPY_EMAIL_INT32(label, targ)
Definition: libpst.c:1999
pst_string return_path_address
mapi element 0x1046, this seems to be the message-id of the rfc822 mail that is being returned ...
Definition: libpst.h:267
pst_string filename2
mapi element 0x3707 PR_ATTACH_LONG_FILENAME
Definition: libpst.h:612
FILETIME * report_time
mapi element 0x0032 PR_REPORT_TIME, delivery report time
Definition: libpst.h:319
pst_string description
mapi element 0x8712
Definition: libpst.h:660
int pst_stricmp(char *a, char *b)
compare strings case-insensitive.
Definition: libpst.c:4231
size_t pst_attach_to_file(pst_file *pf, pst_item_attach *attach, FILE *fp)
Write a binary attachment to a file.
Definition: libpst.c:600
FILETIME * recurrence_end
mapi element 0x8236 PR_OUTLOOK_EVENT_RECURRENCE_END
Definition: libpst.h:773
pst_string business_city
mapi element 0x3a27 PR_BUSINESS_ADDRESS_CITY
Definition: libpst.h:435
int message_recip_me
mapi element 0x0059 PR_MESSAGE_RECIP_ME, this user appears in TO, CC or BCC address list ...
Definition: libpst.h:209
void * pst_realloc(void *ptr, size_t size)
Definition: debug.c:179
#define LIST_COPY_CONTACT_STR(label, targ)
Definition: libpst.c:2085
#define FILE_SIZE_POINTER
Definition: libpst.c:44
pst_string pager_phone
mapi element 0x3a21 PR_PAGER_TELEPHONE_NUMBER
Definition: libpst.h:560
static size_t pst_ff_getIDblock(pst_file *pf, uint64_t i_id, char **buf)
Read a block of data from file into memory.
Definition: libpst.c:4008
struct pst_mapi_element ** elements
Definition: libpst.c:104
pst_desc_tree * pst_getNextDptr(pst_desc_tree *d)
Walk the descriptor tree.
Definition: libpst.c:674
pst_string business_phone
mapi element 0x3a08 PR_BUSINESS_TELEPHONE_NUMBER
Definition: libpst.h:443
uint32_t d_id
Definition: libpst.c:110
#define SAFE_FREE_BIN(x)
Definition: libpst.c:1911
char * pst_rfc2445_datetime_format(const FILETIME *ft, int buflen, char *result)
Convert a FILETIME into rfc2445 date/time format 19531015T231000Z.
Definition: libpst.c:4369
pst_string isdn_phone
mapi element 0x3a2d PR_ISDN_NUMBER
Definition: libpst.h:514
const char * charset
default character set for items without one
Definition: libpst.h:902
#define INDEX_BACK
Definition: libpst.c:46
pst_string office_loc
mapi element 0x3a19 PR_OFFICE_LOCATION
Definition: libpst.h:538
uint64_t id
Definition: libpst.c:142
pst_desc_tree * d_head
the head and tail of the top level of the descriptor tree
Definition: libpst.h:907
char * extra
Definition: libpst.c:96
pst_string recip_address
mapi element 0x0076 PR_RECEIVED_BY_EMAIL_ADDRESS
Definition: libpst.h:255
struct pst_block_offset pst_block_offset
pst_index_ll * id
Definition: libpst.h:120
char * data
Definition: libpst.c:93
uint32_t parm2
Definition: libpst.h:684
#define INDEX_POINTER
Definition: libpst.c:45
struct pst_table3_rec32 pst_table3_rec32
pst_string primary_phone
mapi element 0x3a1a PR_PRIMARY_TELEPHONE_NUMBER
Definition: libpst.h:568
struct pst_desc32 pst_desc32
pst_string gov_id
mapi element 0x3a07 PR_GOVERNMENT_ID_NUMBER
Definition: libpst.h:488
struct pst_id2_tree * next
Definition: libpst.h:122
static uint64_t pst_getIntAt(pst_file *pf, char *buf)
Definition: libpst.c:3902
int32_t ndr_diag_code
mapi element 0x0c05 PR_NDR_DIAG_CODE
Definition: libpst.h:323
#define PST_LE_GET_UINT32(p)
Definition: define.h:235
struct pst_index pst_index
size_t read_size
Definition: libpst.c:80
pst_string other_address
mapi element 0x801c
Definition: libpst.h:544
pst_item_email * email
email mapi elements
Definition: libpst.h:786
#define INDEX_TYPE4K
Definition: libpst.c:27
int response_requested
mapi element 0x0063 PR_RESPONSE_REQUESTED
Definition: libpst.h:851
pst_string personal_homepage
mapi element 0x3a50 PR_PERSONAL_HOME_PAGE
Definition: libpst.h:562
#define PST_TYPE_JOURNAL
Definition: libpst.h:35
pst_string mileage
mapi element 0x8534
Definition: libpst.h:532
pst_entryid * sentmail_folder
mapi element 0x0e0a PR_SENTMAIL_ENTRYID
Definition: libpst.h:313
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)
Process the index1 b-tree from the pst file and create the pf->i_head linked list from it...
Definition: libpst.c:1029
pst_string work_address_postalcode
mapi element 0x8048
Definition: libpst.h:598
int32_t sensitivity
mapi element 0x0036 PR_SENSITIVITY
Definition: libpst.h:309
#define PST_TYPE_APPOINTMENT
Definition: libpst.h:33
#define PST_TYPE_CONTACT
Definition: libpst.h:34
pst_string fullname
mapi element 0x8005
Definition: libpst.h:481
pst_item_attach * attach
linked list of attachments
Definition: libpst.h:792
#define PST_SIGNATURE
Definition: libpst.c:52
#define LIST_COPY_BIN(targ)
Definition: libpst.c:2137
pst_string address1
mapi element 0x3003 PR_EMAIL_ADDRESS, or 0x8083
Definition: libpst.h:401
#define PST_TYPE_OTHER
Definition: libpst.h:38
pst_string pref_name
mapi element 0x3a47 PR_PREFERRED_BY_NAME
Definition: libpst.h:564
pst_string recip2_access
mapi element 0x0077 PR_RCVD_REPRESENTING_ADDRTYPE
Definition: libpst.h:257
void pst_unicode_init()
Definition: vbuf.c:202
FILETIME * start
mapi element 0x820d PR_OUTLOOK_EVENT_START_DATE
Definition: libpst.h:715
pst_string original_to
mapi element 0x0074 PR_ORIGINAL_DISPLAY_TO
Definition: libpst.h:227
static unsigned char comp_enc[]
for "compressible" encryption, just a simple substitution cipher, plaintext = comp_enc[ciphertext]; f...
Definition: libpst.c:209
uint32_t id2
Definition: libpst.c:180
uint64_t id2
Definition: libpst.h:119
FILE * fp
file pointer to opened PST file
Definition: libpst.h:896
pst_string work_address_country
mapi element 0x8049
Definition: libpst.h:600
pst_string business_street
mapi element 0x3a29 PR_BUSINESS_ADDRESS_STREET
Definition: libpst.h:453
struct pst_item_attach * next
Definition: libpst.h:638
int32_t position
mapi element 0x370b PR_RENDERING_POSITION
Definition: libpst.h:635
int16_t u0
Definition: libpst.c:145
struct pst_mapi_object pst_mapi_object
static size_t pst_getAtPos(pst_file *pf, int64_t pos, void *buf, size_t size)
Read part of the pst file.
Definition: libpst.c:3942
uint32_t count
number of occurrences, even if recurrence terminates based on date
Definition: libpst.h:705
pst_string spouse_name
mapi element 0x3a48 PR_SPOUSE_NAME
Definition: libpst.h:578
uint64_t size
Definition: libpst.h:112
#define LIST_COPY_CONTACT_BOOL(label, targ)
Definition: libpst.c:1961
char * pst_base64_encode_multiple(void *data, size_t size, int *line_count)
Definition: libstrfunc.c:35
pst_string business_postal_code
mapi element 0x3a2a PR_BUSINESS_POSTAL_CODE
Definition: libpst.h:449
static int pst_strincmp(char *a, char *b, size_t x)
Definition: libpst.c:4244
static const char * codepage(int cp, int buflen, char *result)
Convert a code page integer into a string suitable for iconv()
Definition: libpst.c:4403
int do_read64
Definition: libpst.h:918
int pst_load_index(pst_file *pf)
Load the index entries from the pst file.
Definition: libpst.c:652
uint16_t to
Definition: libpst.c:57
pst_string other_state
mapi element 0x3a62 PR_OTHER_ADDRESS_STATE_OR_PROVINCE
Definition: libpst.h:556
pst_string rtf_body_tag
mapi element 0x1008 PR_RTF_SYNC_BODY_TAG, the first couple of lines of RTF body so that after modific...
Definition: libpst.h:277
size_t pst_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
fwrite with checking for null pointer.
Definition: libpst.c:4261
struct pst_index64 pst_index64
#define LIST_COPY_ENUM(label, targ, delta, count,...)
Definition: libpst.c:2019
pst_string middle_name
mapi element 0x3a44 PR_MIDDLE_NAME
Definition: libpst.h:530
static void pst_printID2ptr(pst_id2_tree *ptr)
Definition: libpst.c:3766
struct pst_desc_tree * prev
Definition: libpst.h:132
pst_item_folder * folder
folder mapi elements
Definition: libpst.h:788
void pst_convert_utf8_null(pst_item *item, pst_string *str)
Convert str to utf8 if possible; null strings are preserved.
Definition: libpst.c:4535
int32_t rtf_body_crc
mapi element 0x1006 PR_RTF_SYNC_BODY_CRC
Definition: libpst.h:273
pst_string address3_desc
mapi element 0x80a4
Definition: libpst.h:421
pst_string outlook_sender2
mapi element 0x0c1d PR_SENDER_SEARCH_KEY
Definition: libpst.h:239
uint64_t child_id
Definition: libpst.c:184
#define LIST_COPY_INT32(label, targ)
Definition: libpst.c:1994
pst_string original_bcc
mapi element 0x0072 PR_ORIGINAL_DISPLAY_BCC
Definition: libpst.h:223
pst_string other_city
mapi element 0x3a5f PR_OTHER_ADDRESS_CITY
Definition: libpst.h:546
#define PST_ENCRYPT
Definition: libpst.h:45
char * str
Definition: libpst.h:148
static pst_id2_tree * deep_copy(pst_id2_tree *head)
make a deep copy of part of the id2 mapping tree, for use by an attachment containing an embedded rfc...
Definition: libpst.c:532
uint16_t from
Definition: libpst.c:56
pst_id2_tree * id2_head
id2 tree needed to resolve attachments by reference
Definition: libpst.h:624
struct pst_block_header pst_block_header
struct pst_subblock pst_subblock
FILETIME * start
mapi element 0x8706
Definition: libpst.h:654
uint64_t id
Definition: libpst.c:183
#define ITEM_COUNT_OFFSET
Definition: libpst.c:849
int32_t item_count
mapi element 0x3602 PR_CONTENT_COUNT
Definition: libpst.h:345
static size_t pst_ff_getID2block(pst_file *pf, uint64_t id2, pst_id2_tree *id2_head, char **buf)
Definition: libpst.c:4025
pst_string address1a
mapi element 0x8085
Definition: libpst.h:403
#define ENTRY_SIZE_OFFSET
Definition: libpst.c:852
pst_string address3a
mapi element 0x80a5
Definition: libpst.h:419
This contains the recurrence data separated into fields.
Definition: libpst.h:667
int all_day
mapi element 0x8215 PR_OUTLOOK_EVENT_ALL_DAY
Definition: libpst.h:754
pst_index_ll * i_table
the array of index structures
Definition: libpst.h:904
struct pst_file * pf
pointer to the pst_file
Definition: libpst.h:782
#define INDEX_TYPE64
Definition: libpst.c:25
void pst_convert_utf8(pst_item *item, pst_string *str)
Convert str to utf8 if possible; null strings are converted into empty strings.
Definition: libpst.c:4546
pst_string home_phone2
mapi element 0x3a2f PR_HOME2_TELEPHONE_NUMBER
Definition: libpst.h:502
pst_string location
mapi element 0x8208 PR_OUTLOOK_EVENT_LOCATION
Definition: libpst.h:719
pst_string account_name
mapi element 0x3a00 PR_ACCOUNT
Definition: libpst.h:399
pst_string content_id
mapi element 0x3712 PR_ATTACH_CONTENT_ID
Definition: libpst.h:616