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