Mercurial > libpst
annotate src/readpst.c @ 59:7d5c637aaafb
General cleanup and code fixes.
Use autoscan to cleanup our autoconf system.
Use autoconf to detect when we need to use our XGetopt files and other header files.
Decode BCC field.
Fix missing LE32_CPU byte swapping for FILETIME types.
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Thu, 14 Feb 2008 14:55:32 -0800 |
parents | 034641c26ab9 |
children | cfd6175f9334 |
rev | line source |
---|---|
16 | 1 /*** |
2 * readpst.c | |
3 * Part of the LibPST project | |
4 * Written by David Smith | |
43 | 5 * dave.s@earthcorp.com |
16 | 6 */ |
48 | 7 #include "define.h" |
59
7d5c637aaafb
General cleanup and code fixes.
Carl Byington <carl@five-ten-sg.com>
parents:
52
diff
changeset
|
8 #include "libstrfunc.h" |
43 | 9 #include "vbuf.h" |
16 | 10 #include "libpst.h" |
11 #include "common.h" | |
12 #include "timeconv.h" | |
13 #include "lzfu.h" | |
59
7d5c637aaafb
General cleanup and code fixes.
Carl Byington <carl@five-ten-sg.com>
parents:
52
diff
changeset
|
14 |
16 | 15 #define OUTPUT_TEMPLATE "%s" |
16 #define OUTPUT_KMAIL_DIR_TEMPLATE ".%s.directory" | |
17 #define KMAIL_INDEX ".%s.index" | |
25 | 18 #define SEP_MAIL_FILE_TEMPLATE "%i" /* "%09i" */ |
16 | 19 |
20 // max size of the c_time char*. It will store the date of the email | |
21 #define C_TIME_SIZE 500 | |
22 #define PERM_DIRS 0777 | |
23 | |
24 // macro used for creating directories | |
25 #ifndef WIN32 | |
26 #define D_MKDIR(x) mkdir(x, PERM_DIRS) | |
27 #else | |
28 #define D_MKDIR(x) mkdir(x) | |
29 #endif | |
59
7d5c637aaafb
General cleanup and code fixes.
Carl Byington <carl@five-ten-sg.com>
parents:
52
diff
changeset
|
30 |
16 | 31 struct file_ll { |
43 | 32 char *name; |
33 char *dname; | |
34 FILE * output; | |
35 int32_t stored_count; | |
36 int32_t email_count; | |
37 int32_t skip_count; | |
38 int32_t type; | |
16 | 39 }; |
31 | 40 |
43 | 41 void process(pst_item *outeritem, pst_desc_ll *d_ptr); |
42 void write_email_body(FILE *f, char *body); | |
43 char* removeCR (char *c); | |
44 int usage(); | |
45 int version(); | |
46 char* mk_kmail_dir(char*); | |
47 int close_kmail_dir(); | |
48 char* mk_recurse_dir(char*); | |
49 int close_recurse_dir(); | |
50 char* mk_seperate_dir(char *dir); | |
51 int close_seperate_dir(); | |
52 int mk_seperate_file(struct file_ll *f); | |
53 char* my_stristr(char *haystack, char *needle); | |
54 void check_filename(char *fname); | |
55 char* skip_header_prologue(char *headers); | |
56 void write_separate_attachment(char f_name[], pst_item_attach* current_attach, int attach_num, pst_file* pst); | |
57 void write_inline_attachment(FILE* f_output, pst_item_attach* current_attach, char boundary[], pst_file* pst); | |
58 void write_normal_email(FILE* f_output, char f_name[], pst_item* item, int mode, int mode_MH, pst_file* pst, int save_rtf); | |
59 void write_vcard(FILE* f_output, pst_item_contact* contact, char comment[]); | |
60 void write_appointment(FILE* f_output, pst_item_appointment* appointment, | |
61 pst_item_email* email, FILETIME* create_date, FILETIME* modify_date); | |
62 void create_enter_dir(struct file_ll* f, pst_item *item); | |
63 void close_enter_dir(struct file_ll *f); | |
34
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
64 |
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
65 char* prog_name; |
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
66 char* output_dir = "."; |
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
67 char* kmail_chdir = NULL; |
16 | 68 // Normal mode just creates mbox format files in the current directory. Each file is named |
69 // the same as the folder's name that it represents | |
70 #define MODE_NORMAL 0 | |
71 // KMail mode creates a directory structure suitable for being used directly | |
72 // by the KMail application | |
73 #define MODE_KMAIL 1 | |
74 // recurse mode creates a directory structure like the PST file. Each directory | |
75 // contains only one file which stores the emails in mbox format. | |
76 #define MODE_RECURSE 2 | |
77 // seperate mode is similar directory structure to RECURSE. The emails are stored in | |
78 // seperate files, numbering from 1 upward. Attachments belonging to the emails are | |
79 // saved as email_no-filename (e.g. 1-samplefile.doc or 000001-Attachment2.zip) | |
80 #define MODE_SEPERATE 3 | |
43 | 81 // Decrypt the whole file (even the parts that aren't encrypted) and ralph it to stdout |
82 #define MODE_DECSPEW 4 | |
16 | 83 |
84 | |
85 // Output Normal just prints the standard information about what is going on | |
86 #define OUTPUT_NORMAL 0 | |
87 // Output Quiet is provided so that only errors are printed | |
88 #define OUTPUT_QUIET 1 | |
89 | |
90 // default mime-type for attachments that have a null mime-type | |
91 #define MIME_TYPE_DEFAULT "application/octet-stream" | |
92 | |
93 // output mode for contacts | |
94 #define CMODE_VCARD 0 | |
43 | 95 #define CMODE_LIST 1 |
16 | 96 |
97 // output settings for RTF bodies | |
98 // filename for the attachment | |
99 #define RTF_ATTACH_NAME "rtf-body.rtf" | |
100 // mime type for the attachment | |
101 #define RTF_ATTACH_TYPE "application/rtf" | |
34
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
102 |
39 | 103 // global settings |
104 int mode = MODE_NORMAL; | |
105 int mode_MH = 0; | |
106 int output_mode = OUTPUT_NORMAL; | |
107 int contact_mode = CMODE_VCARD; | |
108 int overwrite = 0; | |
109 int save_rtf_body = 1; | |
110 pst_file pstfile; | |
111 | |
112 | |
113 | |
114 void process(pst_item *outeritem, pst_desc_ll *d_ptr) | |
115 { | |
43 | 116 struct file_ll ff; |
117 pst_item *item = NULL; | |
39 | 118 |
43 | 119 DEBUG_ENT("process"); |
120 memset(&ff, 0, sizeof(ff)); | |
121 create_enter_dir(&ff, outeritem); | |
39 | 122 |
43 | 123 while (d_ptr) { |
124 DEBUG_MAIN(("main: New item record\n")); | |
125 if (!d_ptr->desc) { | |
126 DEBUG_WARN(("main: ERROR ?? item's desc record is NULL\n")); | |
127 ff.skip_count++; | |
128 } | |
129 else { | |
130 DEBUG_MAIN(("main: Desc Email ID %#x [d_ptr->id = %#x]\n", d_ptr->desc->id, d_ptr->id)); | |
39 | 131 |
46 | 132 item = pst_parse_item(&pstfile, d_ptr); |
43 | 133 DEBUG_MAIN(("main: About to process item\n")); |
134 if (item && item->email && item->email->subject && item->email->subject->subj) { | |
135 DEBUG_EMAIL(("item->email->subject = %p\n", item->email->subject)); | |
136 DEBUG_EMAIL(("item->email->subject->subj = %p\n", item->email->subject->subj)); | |
137 } | |
138 if (item) { | |
139 if (item->message_store) { | |
140 // there should only be one message_store, and we have already done it | |
141 DIE(("main: A second message_store has been found. Sorry, this must be an error.\n")); | |
142 } | |
39 | 143 |
43 | 144 if (item->folder && d_ptr->child && strcasecmp(item->file_as, "Deleted Items")) { |
145 //if this is a non-empty folder other than deleted items, we want to recurse into it | |
146 if (output_mode != OUTPUT_QUIET) printf("Processing Folder \"%s\"\n", item->file_as); | |
147 process(item, d_ptr->child); | |
148 | |
149 } else if (item->contact && (item->type == PST_TYPE_CONTACT)) { | |
150 // deal with a contact | |
151 // write them to the file, one per line in this format | |
152 // Desc Name <email@address>\n | |
153 if (mode == MODE_SEPERATE) mk_seperate_file(&ff); | |
154 ff.email_count++; | |
155 DEBUG_MAIN(("main: Processing Contact\n")); | |
156 if (ff.type != PST_TYPE_CONTACT) { | |
157 DEBUG_MAIN(("main: I have a contact, but the folder isn't a contacts folder. Processing anyway\n")); | |
158 } | |
159 if (contact_mode == CMODE_VCARD) | |
160 write_vcard(ff.output, item->contact, item->comment); | |
161 else | |
162 fprintf(ff.output, "%s <%s>\n", item->contact->fullname, item->contact->address1); | |
39 | 163 |
43 | 164 } else if (item->email && (item->type == PST_TYPE_NOTE || item->type == PST_TYPE_REPORT)) { |
165 if (mode == MODE_SEPERATE) mk_seperate_file(&ff); | |
166 ff.email_count++; | |
167 DEBUG_MAIN(("main: Processing Email\n")); | |
168 if ((ff.type != PST_TYPE_NOTE) && (ff.type != PST_TYPE_REPORT)) { | |
169 DEBUG_MAIN(("main: I have an email, but the folder isn't an email folder. Processing anyway\n")); | |
170 } | |
171 write_normal_email(ff.output, ff.name, item, mode, mode_MH, &pstfile, save_rtf_body); | |
39 | 172 |
43 | 173 } else if (item->journal && (item->type == PST_TYPE_JOURNAL)) { |
174 // deal with journal items | |
175 if (mode == MODE_SEPERATE) mk_seperate_file(&ff); | |
176 ff.email_count++; | |
177 DEBUG_MAIN(("main: Processing Journal Entry\n")); | |
178 if (ff.type != PST_TYPE_JOURNAL) { | |
179 DEBUG_MAIN(("main: I have a journal entry, but the folder isn't a journal folder. Processing anyway\n")); | |
180 } | |
181 fprintf(ff.output, "BEGIN:VJOURNAL\n"); | |
50 | 182 if (item->email && item->email->subject && item->email->subject->subj) |
43 | 183 fprintf(ff.output, "SUMMARY:%s\n", pst_rfc2426_escape(item->email->subject->subj)); |
50 | 184 if (item->email && item->email->body) |
43 | 185 fprintf(ff.output, "DESCRIPTION:%s\n", pst_rfc2426_escape(item->email->body)); |
186 if (item->journal->start) | |
187 fprintf(ff.output, "DTSTART;VALUE=DATE-TIME:%s\n", pst_rfc2445_datetime_format(item->journal->start)); | |
188 fprintf(ff.output, "END:VJOURNAL\n\n"); | |
39 | 189 |
43 | 190 } else if (item->appointment && (item->type == PST_TYPE_APPOINTMENT)) { |
191 // deal with Calendar appointments | |
192 if (mode == MODE_SEPERATE) mk_seperate_file(&ff); | |
193 ff.email_count++; | |
194 DEBUG_MAIN(("main: Processing Appointment Entry\n")); | |
195 if (ff.type != PST_TYPE_APPOINTMENT) { | |
196 DEBUG_MAIN(("main: I have an appointment, but folder isn't specified as an appointment type. Processing...\n")); | |
197 } | |
198 write_appointment(ff.output, item->appointment, item->email, item->create_date, item->modify_date); | |
39 | 199 |
43 | 200 } else { |
201 ff.skip_count++; | |
202 DEBUG_MAIN(("main: Unknown item type. %i. Ascii1=\"%s\"\n", | |
203 item->type, item->ascii_type)); | |
204 } | |
46 | 205 pst_freeItem(item); |
43 | 206 } else { |
207 ff.skip_count++; | |
208 DEBUG_MAIN(("main: A NULL item was seen\n")); | |
209 } | |
210 d_ptr = d_ptr->next; | |
211 } | |
212 } | |
213 close_enter_dir(&ff); | |
214 DEBUG_RET(); | |
39 | 215 } |
216 | |
217 | |
34
07177825c91b
fix signed/unsigned to allow very small pst files with only leaf nodes
carl
parents:
33
diff
changeset
|
218 |
16 | 219 int main(int argc, char** argv) { |
43 | 220 pst_item *item = NULL; |
221 pst_desc_ll *d_ptr; | |
222 char * fname = NULL; | |
48 | 223 char *d_log = NULL; |
43 | 224 int c,x; |
225 char *temp = NULL; //temporary char pointer | |
226 prog_name = argv[0]; | |
16 | 227 |
43 | 228 // command-line option handling |
229 while ((c = getopt(argc, argv, "bCc:d:hko:qrSMVw"))!= -1) { | |
230 switch (c) { | |
231 case 'b': | |
232 save_rtf_body = 0; | |
233 break; | |
234 case 'C': | |
235 mode = MODE_DECSPEW; | |
236 break; | |
237 case 'c': | |
238 if (optarg && optarg[0]=='v') | |
239 contact_mode=CMODE_VCARD; | |
240 else if (optarg && optarg[0]=='l') | |
241 contact_mode=CMODE_LIST; | |
242 else { | |
243 usage(); | |
244 exit(0); | |
245 } | |
246 break; | |
247 case 'd': | |
248 d_log = optarg; | |
249 break; | |
250 case 'h': | |
251 usage(); | |
252 exit(0); | |
253 break; | |
254 case 'V': | |
255 version(); | |
256 exit(0); | |
257 break; | |
258 case 'k': | |
259 mode = MODE_KMAIL; | |
260 break; | |
261 case 'M': | |
262 mode = MODE_SEPERATE; | |
263 mode_MH = 1; | |
264 break; | |
265 case 'o': | |
266 output_dir = optarg; | |
267 break; | |
268 case 'q': | |
269 output_mode = OUTPUT_QUIET; | |
270 break; | |
271 case 'r': | |
272 mode = MODE_RECURSE; | |
273 break; | |
274 case 'S': | |
275 mode = MODE_SEPERATE; | |
276 break; | |
277 case 'w': | |
278 overwrite = 1; | |
279 break; | |
280 default: | |
281 usage(); | |
282 exit(1); | |
283 break; | |
284 } | |
285 } | |
286 | |
287 if (argc > optind) { | |
288 fname = argv[optind]; | |
289 } else { | |
290 usage(); | |
291 exit(2); | |
292 } | |
293 | |
294 #ifdef DEBUG_ALL | |
295 // force a log file | |
296 if (!d_log) d_log = "readpst.log"; | |
297 #endif // defined DEBUG_ALL | |
298 DEBUG_INIT(d_log); | |
299 DEBUG_REGISTER_CLOSE(); | |
300 DEBUG_ENT("main"); | |
16 | 301 |
43 | 302 if (mode == MODE_DECSPEW) { |
303 FILE *fp; | |
304 char buf[1024]; | |
305 int l=0; | |
306 if (NULL == (fp = fopen(fname, "rb"))) { | |
307 fprintf(stderr, "Couldn't open file %s\n", fname ); | |
52 | 308 DEBUG_RET(); |
43 | 309 return 1; |
310 } | |
39 | 311 |
43 | 312 while (0 != ( l = fread( buf, 1, 1024, fp))) { |
46 | 313 if (0 != pst_decrypt( buf, l, PST_COMP_ENCRYPT)) |
314 fprintf(stderr, "pst_decrypt() failed (I'll try to continue)\n"); | |
16 | 315 |
43 | 316 if (l != fwrite( buf, 1, l, stdout)) { |
317 fprintf(stderr, "Couldn't output to stdout?\n"); | |
52 | 318 DEBUG_RET(); |
43 | 319 return 1; |
320 } | |
321 } | |
52 | 322 DEBUG_RET(); |
43 | 323 return 0; |
324 } | |
16 | 325 |
43 | 326 if (output_mode != OUTPUT_QUIET) printf("Opening PST file and indexes...\n"); |
327 | |
59
7d5c637aaafb
General cleanup and code fixes.
Carl Byington <carl@five-ten-sg.com>
parents:
52
diff
changeset
|
328 RET_DERROR(pst_open(&pstfile, fname), 1, ("Error opening File\n")); |
43 | 329 RET_DERROR(pst_load_index(&pstfile), 2, ("Index Error\n")); |
330 | |
331 pst_load_extended_attributes(&pstfile); | |
16 | 332 |
43 | 333 if (chdir(output_dir)) { |
334 x = errno; | |
335 pst_close(&pstfile); | |
336 DEBUG_RET(); | |
337 DIE(("main: Cannot change to output dir %s: %s\n", output_dir, strerror(x))); | |
338 } | |
339 | |
340 if (output_mode != OUTPUT_QUIET) printf("About to start processing first record...\n"); | |
341 | |
342 d_ptr = pstfile.d_head; // first record is main record | |
46 | 343 item = pst_parse_item(&pstfile, d_ptr); |
43 | 344 if (!item || !item->message_store) { |
345 DEBUG_RET(); | |
346 DIE(("main: Could not get root record\n")); | |
347 } | |
16 | 348 |
43 | 349 // default the file_as to the same as the main filename if it doesn't exist |
350 if (!item->file_as) { | |
351 if (!(temp = strrchr(fname, '/'))) | |
352 if (!(temp = strrchr(fname, '\\'))) | |
353 temp = fname; | |
354 else | |
355 temp++; // get past the "\\" | |
356 else | |
357 temp++; // get past the "/" | |
358 item->file_as = (char*)xmalloc(strlen(temp)+1); | |
359 strcpy(item->file_as, temp); | |
360 DEBUG_MAIN(("file_as was blank, so am using %s\n", item->file_as)); | |
361 } | |
362 DEBUG_MAIN(("main: Root Folder Name: %s\n", item->file_as)); | |
16 | 363 |
43 | 364 d_ptr = pst_getTopOfFolders(&pstfile, item); |
365 if (!d_ptr) { | |
366 DEBUG_RET(); | |
367 DIE(("Top of folders record not found. Cannot continue\n")); | |
368 } | |
16 | 369 |
43 | 370 process(item, d_ptr->child); // do the children of TOPF |
46 | 371 pst_freeItem(item); |
43 | 372 pst_close(&pstfile); |
16 | 373 |
43 | 374 DEBUG_RET(); |
375 return 0; | |
16 | 376 } |
31 | 377 |
378 | |
16 | 379 void write_email_body(FILE *f, char *body) { |
43 | 380 char *n = body; |
381 // DEBUG_MAIN(("write_email_body(): \"%s\"\n", body)); | |
382 DEBUG_ENT("write_email_body"); | |
383 while (n) { | |
384 if (strncmp(body, "From ", 5) == 0) | |
385 fprintf(f, ">"); | |
386 if ((n = strchr(body, '\n'))) { | |
387 n++; | |
388 fwrite(body, n-body, 1, f); //write just a line | |
16 | 389 |
43 | 390 body = n; |
391 } | |
392 } | |
393 fwrite(body, strlen(body), 1, f); | |
394 DEBUG_RET(); | |
16 | 395 } |
31 | 396 |
397 | |
16 | 398 char *removeCR (char *c) { |
43 | 399 // converts /r/n to /n |
400 char *a, *b; | |
401 DEBUG_ENT("removeCR"); | |
402 a = b = c; | |
403 while (*a != '\0') { | |
404 *b = *a; | |
405 if (*a != '\r') | |
406 b++; | |
407 a++; | |
408 } | |
409 *b = '\0'; | |
410 DEBUG_RET(); | |
411 return c; | |
16 | 412 } |
31 | 413 |
414 | |
16 | 415 int usage() { |
43 | 416 DEBUG_ENT("usage"); |
417 version(); | |
418 printf("Usage: %s [OPTIONS] {PST FILENAME}\n", prog_name); | |
419 printf("OPTIONS:\n"); | |
420 printf("\t-b\t- Don't save RTF-Body attachments\n"); | |
421 printf("\t-c[v|l]\t- Set the Contact output mode. -cv = VCard, -cl = EMail list\n"); | |
422 printf("\t-d <filename> \t- Debug to file. This is a binary log. Use readlog to print it\n"); | |
423 printf("\t-h\t- Help. This screen\n"); | |
424 printf("\t-k\t- KMail. Output in kmail format\n"); | |
425 printf("\t-M\t- MH. Write emails in the MH format\n"); | |
426 printf("\t-o <dirname>\t- Output Dir. Directory to write files to. CWD is changed *after* opening pst file\n"); | |
427 printf("\t-q\t- Quiet. Only print error messages\n"); | |
428 printf("\t-r\t- Recursive. Output in a recursive format\n"); | |
429 printf("\t-S\t- Seperate. Write emails in the seperate format\n"); | |
430 printf("\t-V\t- Version. Display program version\n"); | |
431 printf("\t-w\t- Overwrite any output mbox files\n"); | |
432 printf("\t-C\t- Decrypt the entire file and output on stdout (not typically useful)\n"); | |
433 DEBUG_RET(); | |
434 return 0; | |
16 | 435 } |
31 | 436 |
437 | |
16 | 438 int version() { |
43 | 439 DEBUG_ENT("version"); |
50 | 440 printf("ReadPST / LibPST v%s\n", VERSION); |
16 | 441 #if BYTE_ORDER == BIG_ENDIAN |
43 | 442 printf("Big Endian implementation being used.\n"); |
16 | 443 #elif BYTE_ORDER == LITTLE_ENDIAN |
43 | 444 printf("Little Endian implementation being used.\n"); |
16 | 445 #else |
446 # error "Byte order not supported by this library" | |
447 #endif | |
448 #ifdef __GNUC__ | |
43 | 449 printf("GCC %d.%d : %s %s\n", __GNUC__, __GNUC_MINOR__, __DATE__, __TIME__); |
16 | 450 #endif |
43 | 451 DEBUG_RET(); |
452 return 0; | |
16 | 453 } |
31 | 454 |
455 | |
16 | 456 char *mk_kmail_dir(char *fname) { |
43 | 457 //change to that directory |
458 //make a directory based on OUTPUT_KMAIL_DIR_TEMPLATE | |
459 //allocate space for OUTPUT_TEMPLATE and form a char* with fname | |
460 //return that value | |
461 char *dir, *out_name, *index; | |
462 int x; | |
463 DEBUG_ENT("mk_kmail_dir"); | |
464 if (kmail_chdir && chdir(kmail_chdir)) { | |
465 x = errno; | |
466 DIE(("mk_kmail_dir: Cannot change to directory %s: %s\n", kmail_chdir, strerror(x))); | |
467 } | |
468 dir = malloc(strlen(fname)+strlen(OUTPUT_KMAIL_DIR_TEMPLATE)+1); | |
469 sprintf(dir, OUTPUT_KMAIL_DIR_TEMPLATE, fname); | |
470 check_filename(dir); | |
471 if (D_MKDIR(dir)) { | |
472 //error occured | |
473 if (errno != EEXIST) { | |
474 x = errno; | |
475 DIE(("mk_kmail_dir: Cannot create directory %s: %s\n", dir, strerror(x))); | |
476 } | |
477 } | |
478 kmail_chdir = realloc(kmail_chdir, strlen(dir)+1); | |
479 strcpy(kmail_chdir, dir); | |
480 free (dir); | |
16 | 481 |
43 | 482 //we should remove any existing indexes created by KMail, cause they might be different now |
483 index = malloc(strlen(fname)+strlen(KMAIL_INDEX)+1); | |
484 sprintf(index, KMAIL_INDEX, fname); | |
485 unlink(index); | |
486 free(index); | |
16 | 487 |
43 | 488 out_name = malloc(strlen(fname)+strlen(OUTPUT_TEMPLATE)+1); |
489 sprintf(out_name, OUTPUT_TEMPLATE, fname); | |
490 DEBUG_RET(); | |
491 return out_name; | |
16 | 492 } |
31 | 493 |
494 | |
16 | 495 int close_kmail_dir() { |
43 | 496 // change .. |
497 int x; | |
498 DEBUG_ENT("close_kmail_dir"); | |
499 if (kmail_chdir) { //only free kmail_chdir if not NULL. do not change directory | |
500 free(kmail_chdir); | |
501 kmail_chdir = NULL; | |
502 } else { | |
503 if (chdir("..")) { | |
504 x = errno; | |
505 DIE(("close_kmail_dir: Cannot move up dir (..): %s\n", strerror(x))); | |
506 } | |
507 } | |
508 DEBUG_RET(); | |
509 return 0; | |
16 | 510 } |
31 | 511 |
512 | |
16 | 513 // this will create a directory by that name, then make an mbox file inside |
514 // that dir. any subsequent dirs will be created by name, and they will | |
515 // contain mbox files | |
516 char *mk_recurse_dir(char *dir) { | |
43 | 517 int x; |
518 char *out_name; | |
519 DEBUG_ENT("mk_recurse_dir"); | |
520 check_filename(dir); | |
521 if (D_MKDIR (dir)) { | |
522 if (errno != EEXIST) { // not an error because it exists | |
523 x = errno; | |
524 DIE(("mk_recurse_dir: Cannot create directory %s: %s\n", dir, strerror(x))); | |
525 } | |
526 } | |
527 if (chdir (dir)) { | |
528 x = errno; | |
529 DIE(("mk_recurse_dir: Cannot change to directory %s: %s\n", dir, strerror(x))); | |
530 } | |
531 out_name = malloc(strlen("mbox")+1); | |
532 strcpy(out_name, "mbox"); | |
533 DEBUG_RET(); | |
534 return out_name; | |
16 | 535 } |
31 | 536 |
537 | |
16 | 538 int close_recurse_dir() { |
43 | 539 int x; |
540 DEBUG_ENT("close_recurse_dir"); | |
541 if (chdir("..")) { | |
542 x = errno; | |
543 DIE(("close_recurse_dir: Cannot go up dir (..): %s\n", strerror(x))); | |
544 } | |
545 DEBUG_RET(); | |
546 return 0; | |
16 | 547 } |
31 | 548 |
549 | |
39 | 550 char *mk_seperate_dir(char *dir) { |
43 | 551 size_t dirsize = strlen(dir) + 10; |
552 char dir_name[dirsize]; | |
553 int x = 0, y = 0; | |
16 | 554 |
46 | 555 DEBUG_ENT("mk_seperate_dir"); |
43 | 556 do { |
557 if (y == 0) | |
558 snprintf(dir_name, dirsize, "%s", dir); | |
559 else | |
560 snprintf(dir_name, dirsize, "%s" SEP_MAIL_FILE_TEMPLATE, dir, y); // enough for 9 digits allocated above | |
16 | 561 |
43 | 562 check_filename(dir_name); |
563 DEBUG_MAIN(("about to try creating %s\n", dir_name)); | |
564 if (D_MKDIR(dir_name)) { | |
565 if (errno != EEXIST) { // if there is an error, and it doesn't already exist | |
566 x = errno; | |
567 DIE(("mk_seperate_dir: Cannot create directory %s: %s\n", dir, strerror(x))); | |
568 } | |
569 } else { | |
570 break; | |
571 } | |
572 y++; | |
573 } while (overwrite == 0); | |
16 | 574 |
43 | 575 if (chdir(dir_name)) { |
576 x = errno; | |
577 DIE(("mk_recurse_dir: Cannot change to directory %s: %s\n", dir, strerror(x))); | |
578 } | |
16 | 579 |
43 | 580 if (overwrite) { |
581 // we should probably delete all files from this directory | |
16 | 582 #if !defined(WIN32) && !defined(__CYGWIN__) |
43 | 583 DIR * sdir = NULL; |
584 struct dirent *dirent = NULL; | |
585 struct stat filestat; | |
586 if (!(sdir = opendir("./"))) { | |
587 WARN(("mk_seperate_dir: Cannot open dir \"%s\" for deletion of old contents\n", "./")); | |
588 } else { | |
589 while ((dirent = readdir(sdir))) { | |
590 if (lstat(dirent->d_name, &filestat) != -1) | |
591 if (S_ISREG(filestat.st_mode)) { | |
592 if (unlink(dirent->d_name)) { | |
593 y = errno; | |
594 DIE(("mk_seperate_dir: unlink returned error on file %s: %s\n", dirent->d_name, strerror(y))); | |
595 } | |
596 } | |
597 } | |
598 } | |
26 | 599 #endif |
43 | 600 } |
16 | 601 |
43 | 602 // we don't return a filename here cause it isn't necessary. |
603 DEBUG_RET(); | |
604 return NULL; | |
16 | 605 } |
31 | 606 |
607 | |
16 | 608 int close_seperate_dir() { |
43 | 609 int x; |
610 DEBUG_ENT("close_seperate_dir"); | |
611 if (chdir("..")) { | |
612 x = errno; | |
613 DIE(("close_seperate_dir: Cannot go up dir (..): %s\n", strerror(x))); | |
614 } | |
615 DEBUG_RET(); | |
616 return 0; | |
16 | 617 } |
31 | 618 |
619 | |
16 | 620 int mk_seperate_file(struct file_ll *f) { |
43 | 621 const int name_offset = 1; |
622 DEBUG_ENT("mk_seperate_file"); | |
623 DEBUG_MAIN(("opening next file to save email\n")); | |
624 if (f->email_count > 999999999) { // bigger than nine 9's | |
625 DIE(("mk_seperate_file: The number of emails in this folder has become too high to handle")); | |
626 } | |
627 sprintf(f->name, SEP_MAIL_FILE_TEMPLATE, f->email_count + name_offset); | |
628 if (f->output) fclose(f->output); | |
629 f->output = NULL; | |
630 check_filename(f->name); | |
631 if (!(f->output = fopen(f->name, "w"))) { | |
632 DIE(("mk_seperate_file: Cannot open file to save email \"%s\"\n", f->name)); | |
633 } | |
634 DEBUG_RET(); | |
635 return 0; | |
16 | 636 } |
31 | 637 |
638 | |
16 | 639 char *my_stristr(char *haystack, char *needle) { |
43 | 640 // my_stristr varies from strstr in that its searches are case-insensitive |
641 char *x=haystack, *y=needle, *z = NULL; | |
642 DEBUG_ENT("my_stristr"); | |
52 | 643 if (!haystack || !needle) { |
644 DEBUG_RET(); | |
43 | 645 return NULL; |
52 | 646 } |
43 | 647 while (*y != '\0' && *x != '\0') { |
648 if (tolower(*y) == tolower(*x)) { | |
649 // move y on one | |
650 y++; | |
651 if (!z) { | |
652 z = x; // store first position in haystack where a match is made | |
653 } | |
654 } else { | |
655 y = needle; // reset y to the beginning of the needle | |
656 z = NULL; // reset the haystack storage point | |
657 } | |
658 x++; // advance the search in the haystack | |
659 } | |
660 DEBUG_RET(); | |
661 return z; | |
16 | 662 } |
31 | 663 |
664 | |
41
183ae993b9ad
security fix for potential buffer overrun in lz decompress
carl
parents:
39
diff
changeset
|
665 void check_filename(char *fname) { |
43 | 666 char *t = fname; |
667 DEBUG_ENT("check_filename"); | |
668 if (!t) { | |
669 DEBUG_RET(); | |
52 | 670 return; |
43 | 671 } |
672 while ((t = strpbrk(t, "/\\:"))) { | |
673 // while there are characters in the second string that we don't want | |
674 *t = '_'; //replace them with an underscore | |
675 } | |
676 DEBUG_RET(); | |
16 | 677 } |
31 | 678 |
679 | |
16 | 680 // The sole purpose of this function is to bypass the pseudo-header prologue |
681 // that Microsoft Outlook inserts at the beginning of the internet email | |
682 // headers for emails stored in their "Personal Folders" files. | |
683 char *skip_header_prologue(char *headers) { | |
43 | 684 const char *bad = "Microsoft Mail Internet Headers"; |
685 if ( strncmp(headers, bad, strlen(bad)) == 0 ) { | |
686 // Found the offensive header prologue | |
687 char *pc = strchr(headers, '\n'); | |
688 return pc + 1; | |
689 } | |
690 return headers; | |
16 | 691 } |
692 | |
31 | 693 |
25 | 694 void write_separate_attachment(char f_name[], pst_item_attach* current_attach, int attach_num, pst_file* pst) |
695 { | |
43 | 696 FILE *fp = NULL; |
697 int x = 0; | |
698 char *temp = NULL; | |
31 | 699 |
43 | 700 // If there is a long filename (filename2) use that, otherwise |
701 // use the 8.3 filename (filename1) | |
702 char *attach_filename = (current_attach->filename2) ? current_attach->filename2 | |
703 : current_attach->filename1; | |
46 | 704 DEBUG_ENT("write_separate_attachment"); |
25 | 705 |
43 | 706 check_filename(f_name); |
707 if (!attach_filename) { | |
708 // generate our own (dummy) filename for the attachement | |
709 temp = xmalloc(strlen(f_name)+15); | |
710 sprintf(temp, "%s-attach%i", f_name, attach_num); | |
711 } else { | |
712 // have an attachment name, make sure it's unique | |
713 temp = xmalloc(strlen(f_name)+strlen(attach_filename)+15); | |
714 do { | |
715 if (fp) fclose(fp); | |
716 if (x == 0) | |
717 sprintf(temp, "%s-%s", f_name, attach_filename); | |
718 else | |
719 sprintf(temp, "%s-%s-%i", f_name, attach_filename, x); | |
720 } while ((fp = fopen(temp, "r")) && ++x < 99999999); | |
721 if (x > 99999999) { | |
722 DIE(("error finding attachment name. exhausted possibilities to %s\n", temp)); | |
723 } | |
724 } | |
725 DEBUG_EMAIL(("Saving attachment to %s\n", temp)); | |
726 if (!(fp = fopen(temp, "w"))) { | |
727 WARN(("write_separate_attachment: Cannot open attachment save file \"%s\"\n", temp)); | |
728 } else { | |
729 if (current_attach->data) | |
730 fwrite(current_attach->data, 1, current_attach->size, fp); | |
731 else { | |
46 | 732 (void)pst_attach_to_file(pst, current_attach, fp); |
43 | 733 } |
734 fclose(fp); | |
735 } | |
736 if (temp) free(temp); | |
737 DEBUG_RET(); | |
25 | 738 } |
739 | |
31 | 740 |
25 | 741 void write_inline_attachment(FILE* f_output, pst_item_attach* current_attach, char boundary[], pst_file* pst) |
742 { | |
46 | 743 char *enc = NULL; // base64 encoded attachment |
43 | 744 DEBUG_ENT("write_inline_attachment"); |
745 DEBUG_EMAIL(("Attachment Size is %i\n", current_attach->size)); | |
746 DEBUG_EMAIL(("Attachment Pointer is %p\n", current_attach->data)); | |
747 if (current_attach->data) { | |
748 enc = base64_encode (current_attach->data, current_attach->size); | |
749 if (!enc) { | |
750 DEBUG_EMAIL(("ERROR base64_encode returned NULL. Must have failed\n")); | |
52 | 751 DEBUG_RET(); |
43 | 752 return; |
753 } | |
754 } | |
755 if (boundary) { | |
756 char *attach_filename; | |
757 fprintf(f_output, "\n--%s\n", boundary); | |
758 if (!current_attach->mimetype) { | |
759 fprintf(f_output, "Content-type: %s\n", MIME_TYPE_DEFAULT); | |
760 } else { | |
761 fprintf(f_output, "Content-type: %s\n", current_attach->mimetype); | |
762 } | |
763 fprintf(f_output, "Content-transfer-encoding: base64\n"); | |
764 // If there is a long filename (filename2) use that, otherwise | |
765 // use the 8.3 filename (filename1) | |
766 if (current_attach->filename2) { | |
48 | 767 attach_filename = current_attach->filename2; |
43 | 768 } else { |
48 | 769 attach_filename = current_attach->filename1; |
43 | 770 } |
771 if (!attach_filename) { | |
772 fprintf(f_output, "Content-Disposition: inline\n\n"); | |
773 } else { | |
774 fprintf(f_output, "Content-Disposition: attachment; filename=\"%s\"\n\n", attach_filename); | |
775 } | |
776 } | |
777 if (current_attach->data) { | |
778 fwrite(enc, 1, strlen(enc), f_output); | |
779 DEBUG_EMAIL(("Attachment Size after encoding is %i\n", strlen(enc))); | |
780 free(enc); // caught by valgrind | |
781 } else { | |
46 | 782 (void)pst_attach_to_file_base64(pst, current_attach, f_output); |
43 | 783 } |
784 fprintf(f_output, "\n\n"); | |
785 DEBUG_RET(); | |
25 | 786 } |
787 | |
31 | 788 |
789 void write_normal_email(FILE* f_output, char f_name[], pst_item* item, int mode, int mode_MH, pst_file* pst, int save_rtf) | |
25 | 790 { |
43 | 791 char *boundary = NULL; // the boundary marker between multipart sections |
792 int boundary_created = 0; // we have not (yet) created a new boundary | |
793 char *temp = NULL; | |
794 int attach_num, base64_body = 0; | |
795 time_t em_time; | |
796 char *c_time; | |
797 pst_item_attach* current_attach; | |
46 | 798 DEBUG_ENT("write_normal_email"); |
25 | 799 |
43 | 800 // convert the sent date if it exists, or set it to a fixed date |
801 if (item->email->sent_date) { | |
802 em_time = fileTimeToUnixTime(item->email->sent_date, 0); | |
803 c_time = ctime(&em_time); | |
804 if (c_time) | |
805 c_time[strlen(c_time)-1] = '\0'; //remove end \n | |
806 else | |
807 c_time = "Fri Dec 28 12:06:21 2001"; | |
808 } else | |
809 c_time= "Fri Dec 28 12:06:21 2001"; | |
25 | 810 |
43 | 811 // we will always look at the header to discover some stuff |
812 if (item->email->header ) { | |
813 char *b1, *b2; | |
814 // see if there is a boundary variable there | |
815 // this search MUST be made case insensitive (DONE). | |
816 // Also, we should check to find out if we are looking | |
817 // at the boundary associated with content-type, and that | |
818 // the content type really is multipart | |
25 | 819 |
43 | 820 removeCR(item->email->header); |
25 | 821 |
43 | 822 if ((b2 = my_stristr(item->email->header, "boundary="))) { |
823 int len; | |
824 b2 += strlen("boundary="); // move boundary to first char of marker | |
31 | 825 |
43 | 826 if (*b2 == '"') { |
827 b2++; | |
828 b1 = strchr(b2, '"'); // find terminating quote | |
829 } else { | |
830 b1 = b2; | |
831 while (isgraph(*b1)) // find first char that isn't part of boundary | |
832 b1++; | |
833 } | |
834 len = b1 - b2; | |
835 boundary = malloc(len+1); //malloc that length | |
836 strncpy(boundary, b2, len); // copy boundary to another variable | |
837 boundary[len] = '\0'; | |
838 b1 = b2 = boundary; | |
839 while (*b2 != '\0') { // remove any CRs and Tabs | |
840 if (*b2 != '\n' && *b2 != '\r' && *b2 != '\t') { | |
841 *b1 = *b2; | |
842 b1++; | |
843 } | |
844 b2++; | |
845 } | |
846 *b1 = '\0'; | |
31 | 847 |
43 | 848 DEBUG_EMAIL(("Found boundary of - %s\n", boundary)); |
849 } else { | |
850 DEBUG_EMAIL(("boundary not found in header\n")); | |
851 } | |
25 | 852 |
43 | 853 // also possible to set 7bit encoding detection here. |
854 if ((b2 = my_stristr(item->email->header, "Content-Transfer-Encoding:"))) { | |
855 if ((b2 = strchr(b2, ':'))) { | |
856 b2++; // skip to the : at the end of the string | |
31 | 857 |
43 | 858 while (*b2 == ' ' || *b2 == '\t') |
859 b2++; | |
860 if (pst_strincmp(b2, "base64", 6)==0) { | |
861 DEBUG_EMAIL(("body is base64 encoded\n")); | |
862 base64_body = 1; | |
863 } | |
864 } else { | |
865 DEBUG_WARN(("found a ':' during the my_stristr, but not after that..\n")); | |
866 } | |
867 } | |
868 } | |
25 | 869 |
43 | 870 if (!boundary && (item->attach || (item->email->body && item->email->htmlbody) |
871 || item->email->rtf_compressed || item->email->encrypted_body | |
872 || item->email->encrypted_htmlbody)) { | |
873 // we need to create a boundary here. | |
874 DEBUG_EMAIL(("must create own boundary. oh dear.\n")); | |
875 boundary = malloc(50 * sizeof(char)); // allow 50 chars for boundary | |
876 boundary[0] = '\0'; | |
877 sprintf(boundary, "--boundary-LibPST-iamunique-%i_-_-", rand()); | |
878 DEBUG_EMAIL(("created boundary is %s\n", boundary)); | |
879 boundary_created = 1; | |
880 } | |
25 | 881 |
43 | 882 DEBUG_EMAIL(("About to print Header\n")); |
31 | 883 |
43 | 884 if (item && item->email && item->email->subject && item->email->subject->subj) { |
885 DEBUG_EMAIL(("item->email->subject->subj = %s\n", item->email->subject->subj)); | |
886 } | |
31 | 887 |
43 | 888 if (item->email->header) { |
889 int len; | |
890 char *soh = NULL; // real start of headers. | |
31 | 891 |
43 | 892 // some of the headers we get from the file are not properly defined. |
893 // they can contain some email stuff too. We will cut off the header | |
894 // when we see a \n\n or \r\n\r\n | |
895 removeCR(item->email->header); | |
896 temp = strstr(item->email->header, "\n\n"); | |
25 | 897 |
43 | 898 if (temp) { |
899 DEBUG_EMAIL(("Found body text in header\n")); | |
900 temp[1] = '\0'; // stop after first \n | |
901 } | |
31 | 902 |
43 | 903 // Now, write out the header... |
904 soh = skip_header_prologue(item->email->header); | |
905 if (mode != MODE_SEPERATE) { | |
906 // don't put rubbish in if we are doing seperate | |
907 if (strncmp(soh, "X-From_: ", 9) == 0 ) { | |
908 fputs("From ", f_output); | |
909 soh += 9; | |
910 } else | |
911 fprintf(f_output, "From \"%s\" %s\n", item->email->outlook_sender_name, c_time); | |
912 } | |
913 fprintf(f_output, "%s", soh); | |
914 len = strlen(soh); | |
915 if (!len || (soh[len-1] != '\n')) fprintf(f_output, "\n"); | |
31 | 916 |
43 | 917 } else { |
918 //make up our own header! | |
919 if (mode != MODE_SEPERATE) { | |
920 // don't want this first line for this mode | |
921 if (item->email->outlook_sender_name) { | |
922 temp = item->email->outlook_sender_name; | |
923 } else { | |
924 temp = "(readpst_null)"; | |
925 } | |
926 fprintf(f_output, "From \"%s\" %s\n", temp, c_time); | |
927 } | |
31 | 928 |
43 | 929 temp = item->email->outlook_sender; |
930 if (!temp) temp = ""; | |
931 fprintf(f_output, "From: \"%s\" <%s>\n", item->email->outlook_sender_name, temp); | |
31 | 932 |
43 | 933 if (item->email->subject) { |
934 fprintf(f_output, "Subject: %s\n", item->email->subject->subj); | |
935 } else { | |
936 fprintf(f_output, "Subject: \n"); | |
937 } | |
31 | 938 |
43 | 939 fprintf(f_output, "To: %s\n", item->email->sentto_address); |
940 if (item->email->cc_address) { | |
941 fprintf(f_output, "Cc: %s\n", item->email->cc_address); | |
942 } | |
31 | 943 |
43 | 944 if (item->email->sent_date) { |
945 c_time = (char*) xmalloc(C_TIME_SIZE); | |
946 strftime(c_time, C_TIME_SIZE, "%a, %d %b %Y %H:%M:%S %z", gmtime(&em_time)); | |
947 fprintf(f_output, "Date: %s\n", c_time); | |
948 free(c_time); | |
949 } | |
950 } | |
25 | 951 |
43 | 952 fprintf(f_output, "MIME-Version: 1.0\n"); |
953 if (boundary && boundary_created) { | |
954 // if we created the boundary, then it has NOT already been printed | |
955 // in the headers above. | |
956 if (item->attach) { | |
957 // write the boundary stuff if we have attachments | |
958 fprintf(f_output, "Content-type: multipart/mixed;\n\tboundary=\"%s\"\n", boundary); | |
959 } else if (boundary) { | |
960 // else if we have multipart/alternative then tell it so | |
961 fprintf(f_output, "Content-type: multipart/alternative;\n\tboundary=\"%s\"\n", boundary); | |
962 } else if (item->email->htmlbody) { | |
963 fprintf(f_output, "Content-type: text/html\n"); | |
964 } | |
965 } | |
966 fprintf(f_output, "\n"); // start the body | |
967 DEBUG_EMAIL(("About to print Body\n")); | |
25 | 968 |
43 | 969 if (item->email->body) { |
970 if (boundary) { | |
971 fprintf(f_output, "\n--%s\n", boundary); | |
972 fprintf(f_output, "Content-type: text/plain\n"); | |
973 if (base64_body) | |
974 fprintf(f_output, "Content-Transfer-Encoding: base64\n"); | |
975 fprintf(f_output, "\n"); | |
976 } | |
977 removeCR(item->email->body); | |
978 if (base64_body) { | |
979 char *enc = base64_encode(item->email->body, strlen(item->email->body)); | |
980 if (enc) { | |
981 write_email_body(f_output, enc); | |
982 free(enc); | |
983 } | |
984 } | |
985 else { | |
986 write_email_body(f_output, item->email->body); | |
987 } | |
988 } | |
31 | 989 |
43 | 990 if (item->email->htmlbody) { |
991 if (boundary) { | |
992 fprintf(f_output, "\n--%s\n", boundary); | |
993 fprintf(f_output, "Content-type: text/html\n"); | |
994 if (base64_body) fprintf(f_output, "Content-Transfer-Encoding: base64\n"); | |
995 fprintf(f_output, "\n"); | |
996 } | |
997 removeCR(item->email->htmlbody); | |
998 if (base64_body) { | |
999 char *enc = base64_encode(item->email->htmlbody, strlen(item->email->htmlbody)); | |
1000 if (enc) { | |
1001 write_email_body(f_output, enc); | |
1002 free(enc); | |
1003 } | |
1004 } | |
1005 else { | |
1006 write_email_body(f_output, item->email->htmlbody); | |
1007 } | |
1008 } | |
25 | 1009 |
43 | 1010 if (item->email->rtf_compressed && save_rtf) { |
1011 //int32_t tester; | |
1012 DEBUG_EMAIL(("Adding RTF body as attachment\n")); | |
1013 current_attach = (pst_item_attach*)xmalloc(sizeof(pst_item_attach)); | |
1014 memset(current_attach, 0, sizeof(pst_item_attach)); | |
1015 current_attach->next = item->attach; | |
1016 item->attach = current_attach; | |
1017 current_attach->data = lzfu_decompress(item->email->rtf_compressed, item->email->rtf_compressed_size, ¤t_attach->size); | |
1018 current_attach->filename2 = xmalloc(strlen(RTF_ATTACH_NAME)+2); | |
1019 strcpy(current_attach->filename2, RTF_ATTACH_NAME); | |
1020 current_attach->mimetype = xmalloc(strlen(RTF_ATTACH_TYPE)+2); | |
1021 strcpy(current_attach->mimetype, RTF_ATTACH_TYPE); | |
1022 //memcpy(&tester, item->email->rtf_compressed+sizeof(int32_t), sizeof(int32_t)); | |
1023 //LE32_CPU(tester); | |
1024 //printf("lz produced %d bytes, rtf claims %d bytes\n", current_attach->size, tester); | |
1025 } | |
31 | 1026 |
43 | 1027 if (item->email->encrypted_body || item->email->encrypted_htmlbody) { |
1028 // if either the body or htmlbody is encrypted, add them as attachments | |
1029 if (item->email->encrypted_body) { | |
1030 DEBUG_EMAIL(("Adding Encrypted Body as attachment\n")); | |
1031 current_attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach)); | |
1032 memset(current_attach, 0, sizeof(pst_item_attach)); | |
1033 current_attach->next = item->attach; | |
1034 item->attach = current_attach; | |
1035 current_attach->data = item->email->encrypted_body; | |
1036 current_attach->size = item->email->encrypted_body_size; | |
1037 item->email->encrypted_body = NULL; | |
1038 } | |
31 | 1039 |
43 | 1040 if (item->email->encrypted_htmlbody) { |
1041 DEBUG_EMAIL(("Adding encrypted HTML body as attachment\n")); | |
1042 current_attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach)); | |
1043 memset(current_attach, 0, sizeof(pst_item_attach)); | |
1044 current_attach->next = item->attach; | |
1045 item->attach = current_attach; | |
1046 current_attach->data = item->email->encrypted_htmlbody; | |
1047 current_attach->size = item->email->encrypted_htmlbody_size; | |
1048 item->email->encrypted_htmlbody = NULL; | |
1049 } | |
1050 write_email_body(f_output, "The body of this email is encrypted. This isn't supported yet, but the body is now an attachment\n"); | |
1051 } | |
31 | 1052 |
43 | 1053 // attachments |
1054 attach_num = 0; | |
1055 for (current_attach = item->attach; current_attach; current_attach = current_attach->next) { | |
1056 DEBUG_EMAIL(("Attempting Attachment encoding\n")); | |
1057 if (!current_attach->data) { | |
1058 DEBUG_EMAIL(("Data of attachment is NULL!. Size is supposed to be %i\n", current_attach->size)); | |
1059 } | |
1060 if (mode == MODE_SEPERATE && !mode_MH) | |
1061 write_separate_attachment(f_name, current_attach, ++attach_num, pst); | |
1062 else | |
1063 write_inline_attachment(f_output, current_attach, boundary, pst); | |
1064 } | |
1065 if (mode != MODE_SEPERATE) { /* do not add a boundary after the last attachment for mode_MH */ | |
1066 DEBUG_EMAIL(("Writing buffer between emails\n")); | |
1067 if (boundary) fprintf(f_output, "\n--%s--\n", boundary); | |
1068 fprintf(f_output, "\n\n"); | |
1069 } | |
1070 if (boundary) free (boundary); | |
1071 DEBUG_RET(); | |
25 | 1072 } |
1073 | |
31 | 1074 |
25 | 1075 void write_vcard(FILE* f_output, pst_item_contact* contact, char comment[]) |
1076 { | |
43 | 1077 // We can only call rfc escape once per printf, since the second call |
1078 // may free the buffer returned by the first call. | |
1079 // I had tried to place those into a single printf - Carl. | |
39 | 1080 |
43 | 1081 DEBUG_ENT("write_vcard"); |
50 | 1082 // the specification I am following is (hopefully) RFC2426 vCard Mime Directory Profile |
43 | 1083 fprintf(f_output, "BEGIN:VCARD\n"); |
1084 fprintf(f_output, "FN:%s\n", pst_rfc2426_escape(contact->fullname)); | |
39 | 1085 |
43 | 1086 //fprintf(f_output, "N:%s;%s;%s;%s;%s\n", |
1087 fprintf(f_output, "N:%s;", (!contact->surname) ? "" : pst_rfc2426_escape(contact->surname)); | |
1088 fprintf(f_output, "%s;", (!contact->first_name) ? "" : pst_rfc2426_escape(contact->first_name)); | |
1089 fprintf(f_output, "%s;", (!contact->middle_name) ? "" : pst_rfc2426_escape(contact->middle_name)); | |
1090 fprintf(f_output, "%s;", (!contact->display_name_prefix) ? "" : pst_rfc2426_escape(contact->display_name_prefix)); | |
1091 fprintf(f_output, "%s\n", (!contact->suffix) ? "" : pst_rfc2426_escape(contact->suffix)); | |
39 | 1092 |
43 | 1093 if (contact->nickname) |
1094 fprintf(f_output, "NICKNAME:%s\n", pst_rfc2426_escape(contact->nickname)); | |
1095 if (contact->address1) | |
1096 fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address1)); | |
1097 if (contact->address2) | |
1098 fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address2)); | |
1099 if (contact->address3) | |
1100 fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address3)); | |
1101 if (contact->birthday) | |
1102 fprintf(f_output, "BDAY:%s\n", pst_rfc2425_datetime_format(contact->birthday)); | |
39 | 1103 |
43 | 1104 if (contact->home_address) { |
1105 //fprintf(f_output, "ADR;TYPE=home:%s;%s;%s;%s;%s;%s;%s\n", | |
1106 fprintf(f_output, "ADR;TYPE=home:%s;", (!contact->home_po_box) ? "" : pst_rfc2426_escape(contact->home_po_box)); | |
1107 fprintf(f_output, "%s;", ""); // extended Address | |
1108 fprintf(f_output, "%s;", (!contact->home_street) ? "" : pst_rfc2426_escape(contact->home_street)); | |
1109 fprintf(f_output, "%s;", (!contact->home_city) ? "" : pst_rfc2426_escape(contact->home_city)); | |
1110 fprintf(f_output, "%s;", (!contact->home_state) ? "" : pst_rfc2426_escape(contact->home_state)); | |
1111 fprintf(f_output, "%s;", (!contact->home_postal_code) ? "" : pst_rfc2426_escape(contact->home_postal_code)); | |
1112 fprintf(f_output, "%s\n", (!contact->home_country) ? "" : pst_rfc2426_escape(contact->home_country)); | |
1113 fprintf(f_output, "LABEL;TYPE=home:%s\n", pst_rfc2426_escape(contact->home_address)); | |
1114 } | |
39 | 1115 |
43 | 1116 if (contact->business_address) { |
1117 //fprintf(f_output, "ADR;TYPE=work:%s;%s;%s;%s;%s;%s;%s\n", | |
1118 fprintf(f_output, "ADR;TYPE=work:%s;", (!contact->business_po_box) ? "" : pst_rfc2426_escape(contact->business_po_box)); | |
1119 fprintf(f_output, "%s;", ""); // extended Address | |
1120 fprintf(f_output, "%s;", (!contact->business_street) ? "" : pst_rfc2426_escape(contact->business_street)); | |
1121 fprintf(f_output, "%s;", (!contact->business_city) ? "" : pst_rfc2426_escape(contact->business_city)); | |
1122 fprintf(f_output, "%s;", (!contact->business_state) ? "" : pst_rfc2426_escape(contact->business_state)); | |
1123 fprintf(f_output, "%s;", (!contact->business_postal_code) ? "" : pst_rfc2426_escape(contact->business_postal_code)); | |
1124 fprintf(f_output, "%s\n", (!contact->business_country) ? "" : pst_rfc2426_escape(contact->business_country)); | |
1125 fprintf(f_output, "LABEL;TYPE=work:%s\n", pst_rfc2426_escape(contact->business_address)); | |
1126 } | |
39 | 1127 |
43 | 1128 if (contact->other_address) { |
1129 //fprintf(f_output, "ADR;TYPE=postal:%s;%s;%s;%s;%s;%s;%s\n", | |
1130 fprintf(f_output, "ADR;TYPE=postal:%s;",(!contact->other_po_box) ? "" : pst_rfc2426_escape(contact->other_po_box)); | |
1131 fprintf(f_output, "%s;", ""); // extended Address | |
1132 fprintf(f_output, "%s;", (!contact->other_street) ? "" : pst_rfc2426_escape(contact->other_street)); | |
1133 fprintf(f_output, "%s;", (!contact->other_city) ? "" : pst_rfc2426_escape(contact->other_city)); | |
1134 fprintf(f_output, "%s;", (!contact->other_state) ? "" : pst_rfc2426_escape(contact->other_state)); | |
1135 fprintf(f_output, "%s;", (!contact->other_postal_code) ? "" : pst_rfc2426_escape(contact->other_postal_code)); | |
1136 fprintf(f_output, "%s\n", (!contact->other_country) ? "" : pst_rfc2426_escape(contact->other_country)); | |
1137 fprintf(f_output, "LABEL;TYPE=postal:%s\n", pst_rfc2426_escape(contact->other_address)); | |
1138 } | |
39 | 1139 |
43 | 1140 if (contact->business_fax) fprintf(f_output, "TEL;TYPE=work,fax:%s\n", pst_rfc2426_escape(contact->business_fax)); |
1141 if (contact->business_phone) fprintf(f_output, "TEL;TYPE=work,voice:%s\n", pst_rfc2426_escape(contact->business_phone)); | |
1142 if (contact->business_phone2) fprintf(f_output, "TEL;TYPE=work,voice:%s\n", pst_rfc2426_escape(contact->business_phone2)); | |
1143 if (contact->car_phone) fprintf(f_output, "TEL;TYPE=car,voice:%s\n", pst_rfc2426_escape(contact->car_phone)); | |
1144 if (contact->home_fax) fprintf(f_output, "TEL;TYPE=home,fax:%s\n", pst_rfc2426_escape(contact->home_fax)); | |
1145 if (contact->home_phone) fprintf(f_output, "TEL;TYPE=home,voice:%s\n", pst_rfc2426_escape(contact->home_phone)); | |
1146 if (contact->home_phone2) fprintf(f_output, "TEL;TYPE=home,voice:%s\n", pst_rfc2426_escape(contact->home_phone2)); | |
1147 if (contact->isdn_phone) fprintf(f_output, "TEL;TYPE=isdn:%s\n", pst_rfc2426_escape(contact->isdn_phone)); | |
1148 if (contact->mobile_phone) fprintf(f_output, "TEL;TYPE=cell,voice:%s\n", pst_rfc2426_escape(contact->mobile_phone)); | |
1149 if (contact->other_phone) fprintf(f_output, "TEL;TYPE=msg:%s\n", pst_rfc2426_escape(contact->other_phone)); | |
1150 if (contact->pager_phone) fprintf(f_output, "TEL;TYPE=pager:%s\n", pst_rfc2426_escape(contact->pager_phone)); | |
1151 if (contact->primary_fax) fprintf(f_output, "TEL;TYPE=fax,pref:%s\n", pst_rfc2426_escape(contact->primary_fax)); | |
1152 if (contact->primary_phone) fprintf(f_output, "TEL;TYPE=phone,pref:%s\n", pst_rfc2426_escape(contact->primary_phone)); | |
1153 if (contact->radio_phone) fprintf(f_output, "TEL;TYPE=pcs:%s\n", pst_rfc2426_escape(contact->radio_phone)); | |
1154 if (contact->telex) fprintf(f_output, "TEL;TYPE=bbs:%s\n", pst_rfc2426_escape(contact->telex)); | |
1155 if (contact->job_title) fprintf(f_output, "TITLE:%s\n", pst_rfc2426_escape(contact->job_title)); | |
1156 if (contact->profession) fprintf(f_output, "ROLE:%s\n", pst_rfc2426_escape(contact->profession)); | |
1157 if (contact->assistant_name || contact->assistant_phone) { | |
1158 fprintf(f_output, "AGENT:BEGIN:VCARD\n"); | |
1159 if (contact->assistant_name) fprintf(f_output, "FN:%s\n", pst_rfc2426_escape(contact->assistant_name)); | |
1160 if (contact->assistant_phone) fprintf(f_output, "TEL:%s\n", pst_rfc2426_escape(contact->assistant_phone)); | |
1161 } | |
1162 if (contact->company_name) fprintf(f_output, "ORG:%s\n", pst_rfc2426_escape(contact->company_name)); | |
1163 if (comment) fprintf(f_output, "NOTE:%s\n", pst_rfc2426_escape(comment)); | |
25 | 1164 |
43 | 1165 fprintf(f_output, "VERSION: 3.0\n"); |
1166 fprintf(f_output, "END:VCARD\n\n"); | |
1167 DEBUG_RET(); | |
25 | 1168 } |
1169 | |
31 | 1170 |
25 | 1171 void write_appointment(FILE* f_output, pst_item_appointment* appointment, |
43 | 1172 pst_item_email* email, FILETIME* create_date, FILETIME* modify_date) |
25 | 1173 { |
43 | 1174 fprintf(f_output, "BEGIN:VEVENT\n"); |
1175 if (create_date) | |
1176 fprintf(f_output, "CREATED:%s\n", | |
1177 pst_rfc2445_datetime_format(create_date)); | |
1178 if (modify_date) | |
1179 fprintf(f_output, "LAST-MOD:%s\n", | |
1180 pst_rfc2445_datetime_format(modify_date)); | |
1181 if (email && email->subject) | |
1182 fprintf(f_output, "SUMMARY:%s\n", | |
1183 pst_rfc2426_escape(email->subject->subj)); | |
1184 if (email && email->body) | |
1185 fprintf(f_output, "DESCRIPTION:%s\n", | |
1186 pst_rfc2426_escape(email->body)); | |
1187 if (appointment && appointment->start) | |
1188 fprintf(f_output, "DTSTART;VALUE=DATE-TIME:%s\n", | |
1189 pst_rfc2445_datetime_format(appointment->start)); | |
1190 if (appointment && appointment->end) | |
1191 fprintf(f_output, "DTEND;VALUE=DATE-TIME:%s\n", | |
1192 pst_rfc2445_datetime_format(appointment->end)); | |
1193 if (appointment && appointment->location) | |
1194 fprintf(f_output, "LOCATION:%s\n", | |
1195 pst_rfc2426_escape(appointment->location)); | |
1196 if (appointment) { | |
1197 switch (appointment->showas) { | |
50 | 1198 case PST_FREEBUSY_TENTATIVE: |
1199 fprintf(f_output, "STATUS:TENTATIVE\n"); | |
1200 break; | |
1201 case PST_FREEBUSY_FREE: | |
1202 // mark as transparent and as confirmed | |
1203 fprintf(f_output, "TRANSP:TRANSPARENT\n"); | |
1204 case PST_FREEBUSY_BUSY: | |
1205 case PST_FREEBUSY_OUT_OF_OFFICE: | |
1206 fprintf(f_output, "STATUS:CONFIRMED\n"); | |
1207 break; | |
43 | 1208 } |
1209 switch (appointment->label) { | |
50 | 1210 case PST_APP_LABEL_NONE: |
1211 fprintf(f_output, "CATEGORIES:NONE\n"); | |
1212 break; | |
1213 case PST_APP_LABEL_IMPORTANT: | |
1214 fprintf(f_output, "CATEGORIES:IMPORTANT\n"); | |
1215 break; | |
1216 case PST_APP_LABEL_BUSINESS: | |
1217 fprintf(f_output, "CATEGORIES:BUSINESS\n"); | |
1218 break; | |
1219 case PST_APP_LABEL_PERSONAL: | |
1220 fprintf(f_output, "CATEGORIES:PERSONAL\n"); | |
1221 break; | |
1222 case PST_APP_LABEL_VACATION: | |
1223 fprintf(f_output, "CATEGORIES:VACATION\n"); | |
1224 break; | |
1225 case PST_APP_LABEL_MUST_ATTEND: | |
1226 fprintf(f_output, "CATEGORIES:MUST-ATTEND\n"); | |
1227 break; | |
1228 case PST_APP_LABEL_TRAVEL_REQ: | |
1229 fprintf(f_output, "CATEGORIES:TRAVEL-REQUIRED\n"); | |
1230 break; | |
1231 case PST_APP_LABEL_NEEDS_PREP: | |
1232 fprintf(f_output, "CATEGORIES:NEEDS-PREPARATION\n"); | |
1233 break; | |
1234 case PST_APP_LABEL_BIRTHDAY: | |
1235 fprintf(f_output, "CATEGORIES:BIRTHDAY\n"); | |
1236 break; | |
1237 case PST_APP_LABEL_ANNIVERSARY: | |
1238 fprintf(f_output, "CATEGORIES:ANNIVERSARY\n"); | |
1239 break; | |
1240 case PST_APP_LABEL_PHONE_CALL: | |
1241 fprintf(f_output, "CATEGORIES:PHONE-CALL\n"); | |
1242 break; | |
43 | 1243 } |
1244 } | |
1245 fprintf(f_output, "END:VEVENT\n\n"); | |
25 | 1246 } |
1247 | |
31 | 1248 |
39 | 1249 void create_enter_dir(struct file_ll* f, pst_item *item) |
25 | 1250 { |
43 | 1251 f->email_count = 0; |
1252 f->skip_count = 0; | |
1253 f->type = item->type; | |
1254 f->stored_count = (item->folder) ? item->folder->email_count : 0; | |
39 | 1255 |
43 | 1256 DEBUG_ENT("create_enter_dir"); |
1257 if (mode == MODE_KMAIL) | |
1258 f->name = mk_kmail_dir(item->file_as); //create directory and form filename | |
1259 else if (mode == MODE_RECURSE) | |
1260 f->name = mk_recurse_dir(item->file_as); | |
1261 else if (mode == MODE_SEPERATE) { | |
1262 // do similar stuff to recurse here. | |
1263 mk_seperate_dir(item->file_as); | |
1264 f->name = (char*) xmalloc(10); | |
1265 memset(f->name, 0, 10); | |
1266 // sprintf(f->name, SEP_MAIL_FILE_TEMPLATE, f->email_count); | |
1267 } else { | |
1268 f->name = (char*) xmalloc(strlen(item->file_as)+strlen(OUTPUT_TEMPLATE)+1); | |
1269 sprintf(f->name, OUTPUT_TEMPLATE, item->file_as); | |
1270 } | |
25 | 1271 |
43 | 1272 f->dname = (char*) xmalloc(strlen(item->file_as)+1); |
1273 strcpy(f->dname, item->file_as); | |
25 | 1274 |
43 | 1275 if (overwrite != 1) { |
1276 int x = 0; | |
1277 char *temp = (char*) xmalloc (strlen(f->name)+10); //enough room for 10 digits | |
25 | 1278 |
43 | 1279 sprintf(temp, "%s", f->name); |
1280 check_filename(temp); | |
1281 while ((f->output = fopen(temp, "r"))) { | |
1282 DEBUG_MAIN(("need to increase filename because one already exists with that name\n")); | |
1283 DEBUG_MAIN(("- increasing it to %s%d\n", f->name, x)); | |
1284 x++; | |
1285 sprintf(temp, "%s%08d", f->name, x); | |
1286 DEBUG_MAIN(("- trying \"%s\"\n", f->name)); | |
1287 if (x == 99999999) { | |
1288 DIE(("create_enter_dir: Why can I not create a folder %s? I have tried %i extensions...\n", f->name, x)); | |
1289 } | |
1290 fclose(f->output); | |
1291 } | |
1292 if (x > 0) { //then the f->name should change | |
1293 free (f->name); | |
1294 f->name = temp; | |
1295 } else { | |
1296 free(temp); | |
1297 } | |
1298 } | |
25 | 1299 |
43 | 1300 DEBUG_MAIN(("f->name = %s\nitem->folder_name = %s\n", f->name, item->file_as)); |
1301 if (mode != MODE_SEPERATE) { | |
1302 check_filename(f->name); | |
1303 if (!(f->output = fopen(f->name, "w"))) { | |
1304 DIE(("create_enter_dir: Could not open file \"%s\" for write\n", f->name)); | |
1305 } | |
1306 } | |
1307 DEBUG_RET(); | |
25 | 1308 } |
1309 | |
39 | 1310 |
1311 void close_enter_dir(struct file_ll *f) | |
1312 { | |
43 | 1313 DEBUG_MAIN(("main: Email Count for folder %s is %i\n", f->dname, f->email_count)); |
1314 if (output_mode != OUTPUT_QUIET) | |
1315 printf("\t\"%s\" - %i items done, skipped %i, should have been %i\n", | |
1316 f->dname, f->email_count, f->skip_count, f->stored_count); | |
1317 if (f->output) fclose(f->output); | |
1318 free(f->name); | |
1319 free(f->dname); | |
39 | 1320 |
43 | 1321 if (mode == MODE_KMAIL) |
1322 close_kmail_dir(); | |
1323 else if (mode == MODE_RECURSE) | |
1324 close_recurse_dir(); | |
1325 else if (mode == MODE_SEPERATE) | |
1326 close_seperate_dir(); | |
39 | 1327 } |
1328 |