00001
00002
00003
00004
00005
00006
00007
00008 #include "define.h"
00009 #include "lzfu.h"
00010
00011 #define OUTPUT_TEMPLATE "%s"
00012 #define OUTPUT_KMAIL_DIR_TEMPLATE ".%s.directory"
00013 #define KMAIL_INDEX ".%s.index"
00014 #define SEP_MAIL_FILE_TEMPLATE "%i%s"
00015
00016
00017 #define C_TIME_SIZE 500
00018
00019 struct file_ll {
00020 char *name;
00021 char *dname;
00022 FILE * output;
00023 int32_t stored_count;
00024 int32_t item_count;
00025 int32_t skip_count;
00026 int32_t type;
00027 };
00028
00029 int grim_reaper();
00030 pid_t try_fork(char* folder);
00031 void process(pst_item *outeritem, pst_desc_tree *d_ptr);
00032 void write_email_body(FILE *f, char *body);
00033 void removeCR(char *c);
00034 void usage();
00035 void version();
00036 char* mk_kmail_dir(char* fname);
00037 int close_kmail_dir();
00038 char* mk_recurse_dir(char* dir, int32_t folder_type);
00039 int close_recurse_dir();
00040 char* mk_separate_dir(char *dir);
00041 int close_separate_dir();
00042 void mk_separate_file(struct file_ll *f, char *extension);
00043 void close_separate_file(struct file_ll *f);
00044 char* my_stristr(char *haystack, char *needle);
00045 void check_filename(char *fname);
00046 void write_separate_attachment(char f_name[], pst_item_attach* attach, int attach_num, pst_file* pst);
00047 void write_embedded_message(FILE* f_output, pst_item_attach* attach, char *boundary, pst_file* pf, char** extra_mime_headers);
00048 void write_inline_attachment(FILE* f_output, pst_item_attach* attach, char *boundary, pst_file* pst);
00049 int valid_headers(char *header);
00050 void header_has_field(char *header, char *field, int *flag);
00051 void header_get_subfield(char *field, const char *subfield, char *body_subfield, size_t size_subfield);
00052 char* header_get_field(char *header, char *field);
00053 char* header_end_field(char *field);
00054 void header_strip_field(char *header, char *field);
00055 int test_base64(char *body);
00056 void find_html_charset(char *html, char *charset, size_t charsetlen);
00057 void find_rfc822_headers(char** extra_mime_headers);
00058 void write_body_part(FILE* f_output, pst_string *body, char *mime, char *charset, char *boundary, pst_file* pst);
00059 void write_schedule_part_data(FILE* f_output, pst_item* item, const char* sender, const char* method);
00060 void write_schedule_part(FILE* f_output, pst_item* item, const char* sender, const char* boundary);
00061 void write_normal_email(FILE* f_output, char f_name[], pst_item* item, int mode, int mode_MH, pst_file* pst, int save_rtf, char** extra_mime_headers);
00062 void write_vcard(FILE* f_output, pst_item *item, pst_item_contact* contact, char comment[]);
00063 int write_extra_categories(FILE* f_output, pst_item* item);
00064 void write_journal(FILE* f_output, pst_item* item);
00065 void write_appointment(FILE* f_output, pst_item *item);
00066 void create_enter_dir(struct file_ll* f, pst_item *item);
00067 void close_enter_dir(struct file_ll *f);
00068
00069 const char* prog_name;
00070 char* output_dir = ".";
00071 char* kmail_chdir = NULL;
00072
00073
00074
00075 #define MODE_NORMAL 0
00076
00077
00078
00079 #define MODE_KMAIL 1
00080
00081
00082
00083 #define MODE_RECURSE 2
00084
00085
00086
00087
00088 #define MODE_SEPARATE 3
00089
00090
00091
00092 #define OUTPUT_NORMAL 0
00093
00094
00095 #define OUTPUT_QUIET 1
00096
00097
00098 #define MIME_TYPE_DEFAULT "application/octet-stream"
00099 #define RFC822 "message/rfc822"
00100
00101
00102 #define CMODE_VCARD 0
00103 #define CMODE_LIST 1
00104
00105
00106 #define DMODE_EXCLUDE 0
00107 #define DMODE_INCLUDE 1
00108
00109
00110 #define OTMODE_EMAIL 1
00111 #define OTMODE_APPOINTMENT 2
00112 #define OTMODE_JOURNAL 4
00113 #define OTMODE_CONTACT 8
00114
00115
00116
00117 #define RTF_ATTACH_NAME "rtf-body.rtf"
00118
00119 #define RTF_ATTACH_TYPE "application/rtf"
00120
00121
00122 int mode = MODE_NORMAL;
00123 int mode_MH = 0;
00124 int mode_EX = 0;
00125 int mode_thunder = 0;
00126 int output_mode = OUTPUT_NORMAL;
00127 int contact_mode = CMODE_VCARD;
00128 int deleted_mode = DMODE_EXCLUDE;
00129 int output_type_mode = 0xff;
00130 int contact_mode_specified = 0;
00131 int overwrite = 0;
00132 int save_rtf_body = 1;
00133 int file_name_len = 10;
00134 pst_file pstfile;
00135 regex_t meta_charset_pattern;
00136
00137 int number_processors = 1;
00138 int max_children = 0;
00139 int max_child_specified = 0;
00140 int active_children;
00141 pid_t* child_processes;
00142
00143 #ifdef HAVE_SEMAPHORE_H
00144 int shared_memory_id;
00145 sem_t* global_children = NULL;
00146 sem_t* output_mutex = NULL;
00147 #endif
00148
00149
00150 int grim_reaper(int waitall)
00151 {
00152 int available = 0;
00153 #ifdef HAVE_FORK
00154 #ifdef HAVE_SEMAPHORE_H
00155 if (global_children) {
00156
00157
00158
00159 int i,j;
00160 for (i=0; i<active_children; i++) {
00161 int status;
00162 pid_t child = child_processes[i];
00163 pid_t ch = waitpid(child, &status, ((waitall) ? 0 : WNOHANG));
00164 if (ch == child) {
00165
00166
00167
00168
00169
00170
00171 if (WIFSIGNALED(status)) {
00172 int sig = WTERMSIG(status);
00173 DEBUG_INFO(("Process %d terminated with signal %d\n", child, sig));
00174
00175
00176 }
00177
00178 for (j=i; j<active_children-1; j++) {
00179 child_processes[j] = child_processes[j+1];
00180 }
00181 active_children--;
00182 i--;
00183 }
00184 }
00185 sem_getvalue(global_children, &available);
00186
00187
00188 }
00189 #endif
00190 #endif
00191 return available;
00192 }
00193
00194
00195 pid_t try_fork(char *folder)
00196 {
00197 #ifdef HAVE_FORK
00198 #ifdef HAVE_SEMAPHORE_H
00199 int available = grim_reaper(0);
00200 if (available) {
00201 sem_wait(global_children);
00202 pid_t child = fork();
00203 if (child < 0) {
00204
00205 return 0;
00206 }
00207 else if (child == 0) {
00208
00209 active_children = 0;
00210 memset(child_processes, 0, sizeof(pid_t) * max_children);
00211 pst_reopen(&pstfile);
00212 }
00213 else {
00214
00215
00216
00217
00218 child_processes[active_children++] = child;
00219 }
00220 return child;
00221 }
00222 else {
00223 return 0;
00224 }
00225 #endif
00226 #endif
00227 return 0;
00228 }
00229
00230
00231 void process(pst_item *outeritem, pst_desc_tree *d_ptr)
00232 {
00233 struct file_ll ff;
00234 pst_item *item = NULL;
00235
00236 DEBUG_ENT("process");
00237 memset(&ff, 0, sizeof(ff));
00238 create_enter_dir(&ff, outeritem);
00239
00240 for (; d_ptr; d_ptr = d_ptr->next) {
00241 DEBUG_INFO(("New item record\n"));
00242 if (!d_ptr->desc) {
00243 ff.skip_count++;
00244 DEBUG_WARN(("ERROR item's desc record is NULL\n"));
00245 continue;
00246 }
00247 DEBUG_INFO(("Desc Email ID %#"PRIx64" [d_ptr->d_id = %#"PRIx64"]\n", d_ptr->desc->i_id, d_ptr->d_id));
00248
00249 item = pst_parse_item(&pstfile, d_ptr, NULL);
00250 DEBUG_INFO(("About to process item\n"));
00251
00252 if (!item) {
00253 ff.skip_count++;
00254 DEBUG_INFO(("A NULL item was seen\n"));
00255 continue;
00256 }
00257
00258 if (item->subject.str) {
00259 DEBUG_INFO(("item->subject = %s\n", item->subject.str));
00260 }
00261
00262 if (item->folder && item->file_as.str) {
00263 DEBUG_INFO(("Processing Folder \"%s\"\n", item->file_as.str));
00264 if (output_mode != OUTPUT_QUIET) {
00265 pst_debug_lock();
00266 printf("Processing Folder \"%s\"\n", item->file_as.str);
00267 fflush(stdout);
00268 pst_debug_unlock();
00269 }
00270 ff.item_count++;
00271 if (d_ptr->child && (deleted_mode == DMODE_INCLUDE || strcasecmp(item->file_as.str, "Deleted Items"))) {
00272
00273 pid_t parent = getpid();
00274 pid_t child = try_fork(item->file_as.str);
00275 if (child == 0) {
00276
00277 pid_t me = getpid();
00278 process(item, d_ptr->child);
00279 #ifdef HAVE_FORK
00280 #ifdef HAVE_SEMAPHORE_H
00281 if (me != parent) {
00282
00283
00284
00285 sem_post(global_children);
00286 grim_reaper(1);
00287 exit(0);
00288 }
00289 #endif
00290 #endif
00291 }
00292 }
00293
00294 } else if (item->contact && (item->type == PST_TYPE_CONTACT)) {
00295 DEBUG_INFO(("Processing Contact\n"));
00296 if (!(output_type_mode & OTMODE_CONTACT)) {
00297 ff.skip_count++;
00298 DEBUG_INFO(("skipping contact: not in output type list\n"));
00299 }
00300 else {
00301 if (!ff.type) ff.type = item->type;
00302 if ((ff.type != PST_TYPE_CONTACT) && (mode != MODE_SEPARATE)) {
00303 ff.skip_count++;
00304 DEBUG_INFO(("I have a contact, but the folder type %"PRIi32" isn't a contacts folder. Skipping it\n", ff.type));
00305 }
00306 else {
00307 ff.item_count++;
00308 if (mode == MODE_SEPARATE) mk_separate_file(&ff, (mode_EX) ? ".vcf" : "");
00309 if (contact_mode == CMODE_VCARD) {
00310 pst_convert_utf8_null(item, &item->comment);
00311 write_vcard(ff.output, item, item->contact, item->comment.str);
00312 }
00313 else {
00314 pst_convert_utf8(item, &item->contact->fullname);
00315 pst_convert_utf8(item, &item->contact->address1);
00316 fprintf(ff.output, "%s <%s>\n", item->contact->fullname.str, item->contact->address1.str);
00317 }
00318 if (mode == MODE_SEPARATE) close_separate_file(&ff);
00319 }
00320 }
00321
00322 } else if (item->email && ((item->type == PST_TYPE_NOTE) || (item->type == PST_TYPE_SCHEDULE) || (item->type == PST_TYPE_REPORT))) {
00323 DEBUG_INFO(("Processing Email\n"));
00324 if (!(output_type_mode & OTMODE_EMAIL)) {
00325 ff.skip_count++;
00326 DEBUG_INFO(("skipping email: not in output type list\n"));
00327 }
00328 else {
00329 if (!ff.type) ff.type = item->type;
00330 if ((ff.type != PST_TYPE_NOTE) && (ff.type != PST_TYPE_SCHEDULE) && (ff.type != PST_TYPE_REPORT) && (mode != MODE_SEPARATE)) {
00331 ff.skip_count++;
00332 DEBUG_INFO(("I have an email type %"PRIi32", but the folder type %"PRIi32" isn't an email folder. Skipping it\n", item->type, ff.type));
00333 }
00334 else {
00335 char *extra_mime_headers = NULL;
00336 ff.item_count++;
00337 if (mode == MODE_SEPARATE) {
00338
00339 pid_t parent = getpid();
00340 pid_t child = try_fork(item->file_as.str);
00341 if (child == 0) {
00342
00343 pid_t me = getpid();
00344 mk_separate_file(&ff, (mode_EX) ? ".eml" : "");
00345 write_normal_email(ff.output, ff.name, item, mode, mode_MH, &pstfile, save_rtf_body, &extra_mime_headers);
00346 close_separate_file(&ff);
00347 #ifdef HAVE_FORK
00348 #ifdef HAVE_SEMAPHORE_H
00349 if (me != parent) {
00350
00351
00352
00353 sem_post(global_children);
00354 grim_reaper(1);
00355 exit(0);
00356 }
00357 #endif
00358 #endif
00359 }
00360 }
00361 else {
00362
00363 write_normal_email(ff.output, ff.name, item, mode, mode_MH, &pstfile, save_rtf_body, &extra_mime_headers);
00364 }
00365 }
00366 }
00367
00368 } else if (item->journal && (item->type == PST_TYPE_JOURNAL)) {
00369 DEBUG_INFO(("Processing Journal Entry\n"));
00370 if (!(output_type_mode & OTMODE_JOURNAL)) {
00371 ff.skip_count++;
00372 DEBUG_INFO(("skipping journal entry: not in output type list\n"));
00373 }
00374 else {
00375 if (!ff.type) ff.type = item->type;
00376 if ((ff.type != PST_TYPE_JOURNAL) && (mode != MODE_SEPARATE)) {
00377 ff.skip_count++;
00378 DEBUG_INFO(("I have a journal entry, but the folder type %"PRIi32" isn't a journal folder. Skipping it\n", ff.type));
00379 }
00380 else {
00381 ff.item_count++;
00382 if (mode == MODE_SEPARATE) mk_separate_file(&ff, (mode_EX) ? ".ics" : "");
00383 write_journal(ff.output, item);
00384 fprintf(ff.output, "\n");
00385 if (mode == MODE_SEPARATE) close_separate_file(&ff);
00386 }
00387 }
00388
00389 } else if (item->appointment && (item->type == PST_TYPE_APPOINTMENT)) {
00390 DEBUG_INFO(("Processing Appointment Entry\n"));
00391 if (!(output_type_mode & OTMODE_APPOINTMENT)) {
00392 ff.skip_count++;
00393 DEBUG_INFO(("skipping appointment: not in output type list\n"));
00394 }
00395 else {
00396 if (!ff.type) ff.type = item->type;
00397 if ((ff.type != PST_TYPE_APPOINTMENT) && (mode != MODE_SEPARATE)) {
00398 ff.skip_count++;
00399 DEBUG_INFO(("I have an appointment, but the folder type %"PRIi32" isn't an appointment folder. Skipping it\n", ff.type));
00400 }
00401 else {
00402 ff.item_count++;
00403 if (mode == MODE_SEPARATE) mk_separate_file(&ff, (mode_EX) ? ".ics" : "");
00404 write_schedule_part_data(ff.output, item, NULL, NULL);
00405 fprintf(ff.output, "\n");
00406 if (mode == MODE_SEPARATE) close_separate_file(&ff);
00407 }
00408 }
00409
00410 } else if (item->message_store) {
00411
00412 ff.skip_count++;
00413 DEBUG_INFO(("item with message store content, type %i %s folder type %i, skipping it\n", item->type, item->ascii_type, ff.type));
00414
00415 } else {
00416 ff.skip_count++;
00417 DEBUG_INFO(("Unknown item type %i (%s) name (%s)\n",
00418 item->type, item->ascii_type, item->file_as.str));
00419 }
00420 pst_freeItem(item);
00421 }
00422 close_enter_dir(&ff);
00423 DEBUG_RET();
00424 }
00425
00426
00427
00428 int main(int argc, char* const* argv) {
00429 pst_item *item = NULL;
00430 pst_desc_tree *d_ptr;
00431 char * fname = NULL;
00432 char *d_log = NULL;
00433 int c,x;
00434 char *temp = NULL;
00435 prog_name = argv[0];
00436
00437 time_t now = time(NULL);
00438 srand((unsigned)now);
00439
00440 if (regcomp(&meta_charset_pattern, "<meta[^>]*content=\"[^>]*charset=([^>\";]*)[\";]", REG_ICASE | REG_EXTENDED)) {
00441 printf("cannot compile regex pattern to find content charset in html bodies\n");
00442 exit(3);
00443 }
00444
00445
00446 while ((c = getopt(argc, argv, "bc:Dd:ehj:kMo:qrSt:uVw"))!= -1) {
00447 switch (c) {
00448 case 'b':
00449 save_rtf_body = 0;
00450 break;
00451 case 'c':
00452 if (optarg && optarg[0]=='v') {
00453 contact_mode=CMODE_VCARD;
00454 contact_mode_specified = 1;
00455 }
00456 else if (optarg && optarg[0]=='l') {
00457 contact_mode=CMODE_LIST;
00458 contact_mode_specified = 1;
00459 }
00460 else {
00461 usage();
00462 exit(0);
00463 }
00464 break;
00465 case 'D':
00466 deleted_mode = DMODE_INCLUDE;
00467 break;
00468 case 'd':
00469 d_log = optarg;
00470 break;
00471 case 'h':
00472 usage();
00473 exit(0);
00474 break;
00475 case 'j':
00476 max_children = atoi(optarg);
00477 max_child_specified = 1;
00478 break;
00479 case 'k':
00480 mode = MODE_KMAIL;
00481 break;
00482 case 'M':
00483 mode = MODE_SEPARATE;
00484 mode_MH = 1;
00485 mode_EX = 0;
00486 break;
00487 case 'e':
00488 mode = MODE_SEPARATE;
00489 mode_MH = 1;
00490 mode_EX = 1;
00491 file_name_len = 14;
00492 break;
00493 case 'o':
00494 output_dir = optarg;
00495 break;
00496 case 'q':
00497 output_mode = OUTPUT_QUIET;
00498 break;
00499 case 'r':
00500 mode = MODE_RECURSE;
00501 mode_thunder = 0;
00502 break;
00503 case 'S':
00504 mode = MODE_SEPARATE;
00505 mode_MH = 0;
00506 mode_EX = 0;
00507 break;
00508 case 't':
00509
00510 if (!optarg) {
00511 usage();
00512 exit(0);
00513 }
00514 temp = optarg;
00515 output_type_mode = 0;
00516 while (*temp > 0) {
00517 switch (temp[0]) {
00518 case 'e':
00519 output_type_mode |= OTMODE_EMAIL;
00520 break;
00521 case 'a':
00522 output_type_mode |= OTMODE_APPOINTMENT;
00523 break;
00524 case 'j':
00525 output_type_mode |= OTMODE_JOURNAL;
00526 break;
00527 case 'c':
00528 output_type_mode |= OTMODE_CONTACT;
00529 break;
00530 default:
00531 usage();
00532 exit(0);
00533 break;
00534 }
00535 temp++;
00536 }
00537 break;
00538 case 'u':
00539 mode = MODE_RECURSE;
00540 mode_thunder = 1;
00541 break;
00542 case 'V':
00543 version();
00544 exit(0);
00545 break;
00546 case 'w':
00547 overwrite = 1;
00548 break;
00549 default:
00550 usage();
00551 exit(1);
00552 break;
00553 }
00554 }
00555
00556 if (argc > optind) {
00557 fname = argv[optind];
00558 } else {
00559 usage();
00560 exit(2);
00561 }
00562
00563 #ifdef _SC_NPROCESSORS_ONLN
00564 number_processors = sysconf(_SC_NPROCESSORS_ONLN);
00565 #endif
00566 max_children = (max_child_specified) ? max_children : number_processors * 4;
00567 active_children = 0;
00568 child_processes = (pid_t *)pst_malloc(sizeof(pid_t) * max_children);
00569 memset(child_processes, 0, sizeof(pid_t) * max_children);
00570
00571 #ifdef HAVE_SEMAPHORE_H
00572 if (max_children) {
00573 shared_memory_id = shmget(IPC_PRIVATE, sizeof(sem_t)*2, 0777);
00574 if (shared_memory_id >= 0) {
00575 global_children = (sem_t *)shmat(shared_memory_id, NULL, 0);
00576 if (global_children == (sem_t *)-1) global_children = NULL;
00577 if (global_children) {
00578 output_mutex = &(global_children[1]);
00579 sem_init(global_children, 1, max_children);
00580 sem_init(output_mutex, 1, 1);
00581 }
00582 shmctl(shared_memory_id, IPC_RMID, NULL);
00583 }
00584 }
00585 #endif
00586
00587 #ifdef DEBUG_ALL
00588
00589 if (!d_log) d_log = "readpst.log";
00590 #endif // defined DEBUG_ALL
00591 #ifdef HAVE_SEMAPHORE_H
00592 DEBUG_INIT(d_log, output_mutex);
00593 #else
00594 DEBUG_INIT(d_log, NULL);
00595 #endif
00596 DEBUG_ENT("main");
00597
00598 if (output_mode != OUTPUT_QUIET) printf("Opening PST file and indexes...\n");
00599
00600 RET_DERROR(pst_open(&pstfile, fname), 1, ("Error opening File\n"));
00601 RET_DERROR(pst_load_index(&pstfile), 2, ("Index Error\n"));
00602
00603 pst_load_extended_attributes(&pstfile);
00604
00605 if (chdir(output_dir)) {
00606 x = errno;
00607 pst_close(&pstfile);
00608 DEBUG_RET();
00609 DIE(("Cannot change to output dir %s: %s\n", output_dir, strerror(x)));
00610 }
00611
00612 d_ptr = pstfile.d_head;
00613 item = pst_parse_item(&pstfile, d_ptr, NULL);
00614 if (!item || !item->message_store) {
00615 DEBUG_RET();
00616 DIE(("Could not get root record\n"));
00617 }
00618
00619
00620 if (!item->file_as.str) {
00621 if (!(temp = strrchr(fname, '/')))
00622 if (!(temp = strrchr(fname, '\\')))
00623 temp = fname;
00624 else
00625 temp++;
00626 else
00627 temp++;
00628 item->file_as.str = (char*)pst_malloc(strlen(temp)+1);
00629 strcpy(item->file_as.str, temp);
00630 item->file_as.is_utf8 = 1;
00631 DEBUG_INFO(("file_as was blank, so am using %s\n", item->file_as.str));
00632 }
00633 DEBUG_INFO(("Root Folder Name: %s\n", item->file_as.str));
00634
00635 d_ptr = pst_getTopOfFolders(&pstfile, item);
00636 if (!d_ptr) {
00637 DEBUG_RET();
00638 DIE(("Top of folders record not found. Cannot continue\n"));
00639 }
00640
00641 process(item, d_ptr->child);
00642 grim_reaper(1);
00643
00644 pst_freeItem(item);
00645 pst_close(&pstfile);
00646 DEBUG_RET();
00647
00648 #ifdef HAVE_SEMAPHORE_H
00649 if (global_children) {
00650 sem_destroy(global_children);
00651 sem_destroy(output_mutex);
00652 shmdt(global_children);
00653 }
00654 #endif
00655
00656 regfree(&meta_charset_pattern);
00657 return 0;
00658 }
00659
00660
00661 void write_email_body(FILE *f, char *body) {
00662 char *n = body;
00663 DEBUG_ENT("write_email_body");
00664 if (mode != MODE_SEPARATE) {
00665 while (n) {
00666 char *p = body;
00667 while (*p == '>') p++;
00668 if (strncmp(p, "From ", 5) == 0) fprintf(f, ">");
00669 if ((n = strchr(body, '\n'))) {
00670 n++;
00671 pst_fwrite(body, n-body, 1, f);
00672 body = n;
00673 }
00674 }
00675 }
00676 pst_fwrite(body, strlen(body), 1, f);
00677 DEBUG_RET();
00678 }
00679
00680
00681 void removeCR (char *c) {
00682
00683 char *a, *b;
00684 DEBUG_ENT("removeCR");
00685 a = b = c;
00686 while (*a != '\0') {
00687 *b = *a;
00688 if (*a != '\r') b++;
00689 a++;
00690 }
00691 *b = '\0';
00692 DEBUG_RET();
00693 }
00694
00695
00696 void usage() {
00697 DEBUG_ENT("usage");
00698 version();
00699 printf("Usage: %s [OPTIONS] {PST FILENAME}\n", prog_name);
00700 printf("OPTIONS:\n");
00701 printf("\t-V\t- Version. Display program version\n");
00702 printf("\t-D\t- Include deleted items in output\n");
00703 printf("\t-M\t- Write emails in the MH (rfc822) format\n");
00704 printf("\t-S\t- Separate. Write emails in the separate format\n");
00705 printf("\t-b\t- Don't save RTF-Body attachments\n");
00706 printf("\t-c[v|l]\t- Set the Contact output mode. -cv = VCard, -cl = EMail list\n");
00707 printf("\t-d <filename> \t- Debug to file.\n");
00708 printf("\t-e\t- As with -M, but include extensions on output files\n");
00709 printf("\t-h\t- Help. This screen\n");
00710 printf("\t-j <integer>\t- Number of parallel jobs to run\n");
00711 printf("\t-k\t- KMail. Output in kmail format\n");
00712 printf("\t-o <dirname>\t- Output directory to write files to. CWD is changed *after* opening pst file\n");
00713 printf("\t-q\t- Quiet. Only print error messages\n");
00714 printf("\t-r\t- Recursive. Output in a recursive format\n");
00715 printf("\t-t[eajc]\t- Set the output type list. e = email, a = attachment, j = journal, c = contact\n");
00716 printf("\t-u\t- Thunderbird mode. Write two extra .size and .type files\n");
00717 printf("\t-w\t- Overwrite any output mbox files\n");
00718 printf("\n");
00719 printf("Only one of -k -M -r -S should be specified\n");
00720 DEBUG_RET();
00721 }
00722
00723
00724 void version() {
00725 DEBUG_ENT("version");
00726 printf("ReadPST / LibPST v%s\n", VERSION);
00727 #if BYTE_ORDER == BIG_ENDIAN
00728 printf("Big Endian implementation being used.\n");
00729 #elif BYTE_ORDER == LITTLE_ENDIAN
00730 printf("Little Endian implementation being used.\n");
00731 #else
00732 # error "Byte order not supported by this library"
00733 #endif
00734 DEBUG_RET();
00735 }
00736
00737
00738 char *mk_kmail_dir(char *fname) {
00739
00740
00741
00742
00743 char *dir, *out_name, *index;
00744 int x;
00745 DEBUG_ENT("mk_kmail_dir");
00746 if (kmail_chdir && chdir(kmail_chdir)) {
00747 x = errno;
00748 DIE(("mk_kmail_dir: Cannot change to directory %s: %s\n", kmail_chdir, strerror(x)));
00749 }
00750 dir = pst_malloc(strlen(fname)+strlen(OUTPUT_KMAIL_DIR_TEMPLATE)+1);
00751 sprintf(dir, OUTPUT_KMAIL_DIR_TEMPLATE, fname);
00752 check_filename(dir);
00753 if (D_MKDIR(dir)) {
00754 if (errno != EEXIST) {
00755 x = errno;
00756 DIE(("mk_kmail_dir: Cannot create directory %s: %s\n", dir, strerror(x)));
00757 }
00758 }
00759 kmail_chdir = pst_realloc(kmail_chdir, strlen(dir)+1);
00760 strcpy(kmail_chdir, dir);
00761 free (dir);
00762
00763
00764 index = pst_malloc(strlen(fname)+strlen(KMAIL_INDEX)+1);
00765 sprintf(index, KMAIL_INDEX, fname);
00766 unlink(index);
00767 free(index);
00768
00769 out_name = pst_malloc(strlen(fname)+strlen(OUTPUT_TEMPLATE)+1);
00770 sprintf(out_name, OUTPUT_TEMPLATE, fname);
00771 DEBUG_RET();
00772 return out_name;
00773 }
00774
00775
00776 int close_kmail_dir() {
00777
00778 int x;
00779 DEBUG_ENT("close_kmail_dir");
00780 if (kmail_chdir) {
00781 free(kmail_chdir);
00782 kmail_chdir = NULL;
00783 } else {
00784 if (chdir("..")) {
00785 x = errno;
00786 DIE(("close_kmail_dir: Cannot move up dir (..): %s\n", strerror(x)));
00787 }
00788 }
00789 DEBUG_RET();
00790 return 0;
00791 }
00792
00793
00794
00795
00796 char *mk_recurse_dir(char *dir, int32_t folder_type) {
00797 int x;
00798 char *out_name;
00799 DEBUG_ENT("mk_recurse_dir");
00800 check_filename(dir);
00801 if (D_MKDIR (dir)) {
00802 if (errno != EEXIST) {
00803 x = errno;
00804 DIE(("mk_recurse_dir: Cannot create directory %s: %s\n", dir, strerror(x)));
00805 }
00806 }
00807 if (chdir (dir)) {
00808 x = errno;
00809 DIE(("mk_recurse_dir: Cannot change to directory %s: %s\n", dir, strerror(x)));
00810 }
00811 switch (folder_type) {
00812 case PST_TYPE_APPOINTMENT:
00813 out_name = strdup("calendar");
00814 break;
00815 case PST_TYPE_CONTACT:
00816 out_name = strdup("contacts");
00817 break;
00818 case PST_TYPE_JOURNAL:
00819 out_name = strdup("journal");
00820 break;
00821 case PST_TYPE_STICKYNOTE:
00822 case PST_TYPE_TASK:
00823 case PST_TYPE_NOTE:
00824 case PST_TYPE_OTHER:
00825 case PST_TYPE_REPORT:
00826 default:
00827 out_name = strdup("mbox");
00828 break;
00829 }
00830 DEBUG_RET();
00831 return out_name;
00832 }
00833
00834
00835 int close_recurse_dir() {
00836 int x;
00837 DEBUG_ENT("close_recurse_dir");
00838 if (chdir("..")) {
00839 x = errno;
00840 DIE(("close_recurse_dir: Cannot go up dir (..): %s\n", strerror(x)));
00841 }
00842 DEBUG_RET();
00843 return 0;
00844 }
00845
00846
00847 char *mk_separate_dir(char *dir) {
00848 size_t dirsize = strlen(dir) + 10;
00849 char dir_name[dirsize];
00850 int x = 0, y = 0;
00851
00852 DEBUG_ENT("mk_separate_dir");
00853 do {
00854 if (y == 0)
00855 snprintf(dir_name, dirsize, "%s", dir);
00856 else
00857 snprintf(dir_name, dirsize, "%s" SEP_MAIL_FILE_TEMPLATE, dir, y, "");
00858
00859 check_filename(dir_name);
00860 DEBUG_INFO(("about to try creating %s\n", dir_name));
00861 if (D_MKDIR(dir_name)) {
00862 if (errno != EEXIST) {
00863 x = errno;
00864 DIE(("mk_separate_dir: Cannot create directory %s: %s\n", dir, strerror(x)));
00865 }
00866 } else {
00867 break;
00868 }
00869 y++;
00870 } while (overwrite == 0);
00871
00872 if (chdir(dir_name)) {
00873 x = errno;
00874 DIE(("mk_separate_dir: Cannot change to directory %s: %s\n", dir, strerror(x)));
00875 }
00876
00877 if (overwrite) {
00878
00879 #if !defined(WIN32) && !defined(__CYGWIN__)
00880 DIR * sdir = NULL;
00881 struct dirent *dirent = NULL;
00882 struct stat filestat;
00883 if (!(sdir = opendir("./"))) {
00884 DEBUG_WARN(("mk_separate_dir: Cannot open dir \"%s\" for deletion of old contents\n", "./"));
00885 } else {
00886 while ((dirent = readdir(sdir))) {
00887 if (lstat(dirent->d_name, &filestat) != -1)
00888 if (S_ISREG(filestat.st_mode)) {
00889 if (unlink(dirent->d_name)) {
00890 y = errno;
00891 DIE(("mk_separate_dir: unlink returned error on file %s: %s\n", dirent->d_name, strerror(y)));
00892 }
00893 }
00894 }
00895 }
00896 #endif
00897 }
00898
00899
00900 DEBUG_RET();
00901 return NULL;
00902 }
00903
00904
00905 int close_separate_dir() {
00906 int x;
00907 DEBUG_ENT("close_separate_dir");
00908 if (chdir("..")) {
00909 x = errno;
00910 DIE(("close_separate_dir: Cannot go up dir (..): %s\n", strerror(x)));
00911 }
00912 DEBUG_RET();
00913 return 0;
00914 }
00915
00916
00917 void mk_separate_file(struct file_ll *f, char *extension) {
00918 DEBUG_ENT("mk_separate_file");
00919 DEBUG_INFO(("opening next file to save email\n"));
00920 if (f->item_count > 999999999) {
00921 DIE(("mk_separate_file: The number of emails in this folder has become too high to handle\n"));
00922 }
00923 sprintf(f->name, SEP_MAIL_FILE_TEMPLATE, f->item_count, extension);
00924 check_filename(f->name);
00925 if (!(f->output = fopen(f->name, "w"))) {
00926 DIE(("mk_separate_file: Cannot open file to save email \"%s\"\n", f->name));
00927 }
00928 DEBUG_RET();
00929 }
00930
00931
00932 void close_separate_file(struct file_ll *f) {
00933 DEBUG_ENT("close_separate_file");
00934 if (f->output) {
00935 struct stat st;
00936 fclose(f->output);
00937 stat(f->name, &st);
00938 if (!st.st_size) {
00939 DEBUG_WARN(("removing empty output file %s\n", f->name));
00940 remove(f->name);
00941 }
00942 f->output = NULL;
00943 }
00944 DEBUG_RET();
00945 }
00946
00947
00948 char *my_stristr(char *haystack, char *needle) {
00949
00950 char *x=haystack, *y=needle, *z = NULL;
00951 if (!haystack || !needle) {
00952 return NULL;
00953 }
00954 while (*y != '\0' && *x != '\0') {
00955 if (tolower(*y) == tolower(*x)) {
00956
00957 y++;
00958 if (!z) {
00959 z = x;
00960 }
00961 } else {
00962 y = needle;
00963 z = NULL;
00964 }
00965 x++;
00966 }
00967
00968 if (*y != '\0') return NULL;
00969 return z;
00970 }
00971
00972
00973 void check_filename(char *fname) {
00974 char *t = fname;
00975 DEBUG_ENT("check_filename");
00976 if (!t) {
00977 DEBUG_RET();
00978 return;
00979 }
00980 while ((t = strpbrk(t, "/\\:"))) {
00981
00982 *t = '_';
00983 }
00984 DEBUG_RET();
00985 }
00986
00987
00988 void write_separate_attachment(char f_name[], pst_item_attach* attach, int attach_num, pst_file* pst)
00989 {
00990 FILE *fp = NULL;
00991 int x = 0;
00992 char *temp = NULL;
00993
00994
00995
00996 char *attach_filename = (attach->filename2.str) ? attach->filename2.str
00997 : attach->filename1.str;
00998 DEBUG_ENT("write_separate_attachment");
00999 DEBUG_INFO(("Attachment %s Size is %#"PRIx64", data = %#"PRIxPTR", id %#"PRIx64"\n", attach_filename, (uint64_t)attach->data.size, attach->data.data, attach->i_id));
01000
01001 if (!attach->data.data) {
01002
01003 pst_index_ll *ptr = pst_getID(pst, attach->i_id);
01004 if (!ptr) {
01005 DEBUG_WARN(("Couldn't find i_id %#"PRIx64". Cannot save attachment to file\n", attach->i_id));
01006 DEBUG_RET();
01007 return;
01008 }
01009 }
01010
01011 check_filename(f_name);
01012 if (!attach_filename) {
01013
01014 temp = pst_malloc(strlen(f_name)+15);
01015 sprintf(temp, "%s-attach%i", f_name, attach_num);
01016 } else {
01017
01018 temp = pst_malloc(strlen(f_name)+strlen(attach_filename)+15);
01019 do {
01020 if (fp) fclose(fp);
01021 if (x == 0)
01022 sprintf(temp, "%s-%s", f_name, attach_filename);
01023 else
01024 sprintf(temp, "%s-%s-%i", f_name, attach_filename, x);
01025 } while ((fp = fopen(temp, "r")) && ++x < 99999999);
01026 if (x > 99999999) {
01027 DIE(("error finding attachment name. exhausted possibilities to %s\n", temp));
01028 }
01029 }
01030 DEBUG_INFO(("Saving attachment to %s\n", temp));
01031 if (!(fp = fopen(temp, "w"))) {
01032 DEBUG_WARN(("write_separate_attachment: Cannot open attachment save file \"%s\"\n", temp));
01033 } else {
01034 (void)pst_attach_to_file(pst, attach, fp);
01035 fclose(fp);
01036 }
01037 if (temp) free(temp);
01038 DEBUG_RET();
01039 }
01040
01041
01042 void write_embedded_message(FILE* f_output, pst_item_attach* attach, char *boundary, pst_file* pf, char** extra_mime_headers)
01043 {
01044 pst_index_ll *ptr;
01045 DEBUG_ENT("write_embedded_message");
01046 ptr = pst_getID(pf, attach->i_id);
01047
01048 pst_desc_tree d_ptr;
01049 d_ptr.d_id = 0;
01050 d_ptr.parent_d_id = 0;
01051 d_ptr.assoc_tree = NULL;
01052 d_ptr.desc = ptr;
01053 d_ptr.no_child = 0;
01054 d_ptr.prev = NULL;
01055 d_ptr.next = NULL;
01056 d_ptr.parent = NULL;
01057 d_ptr.child = NULL;
01058 d_ptr.child_tail = NULL;
01059
01060 pst_item *item = pst_parse_item(pf, &d_ptr, attach->id2_head);
01061
01062
01063
01064
01065
01066
01067 if (!item) {
01068 DEBUG_WARN(("write_embedded_message: pst_parse_item was unable to parse the embedded message in attachment ID %llu", attach->i_id));
01069 } else {
01070 if (!item->email) {
01071 DEBUG_WARN(("write_embedded_message: pst_parse_item returned type %d, not an email message", item->type));
01072 } else {
01073 fprintf(f_output, "\n--%s\n", boundary);
01074 fprintf(f_output, "Content-Type: %s\n\n", attach->mimetype.str);
01075 write_normal_email(f_output, "", item, MODE_NORMAL, 0, pf, 0, extra_mime_headers);
01076 }
01077 pst_freeItem(item);
01078 }
01079
01080 DEBUG_RET();
01081 }
01082
01083
01084 void write_inline_attachment(FILE* f_output, pst_item_attach* attach, char *boundary, pst_file* pst)
01085 {
01086 DEBUG_ENT("write_inline_attachment");
01087 DEBUG_INFO(("Attachment Size is %#"PRIx64", data = %#"PRIxPTR", id %#"PRIx64"\n", (uint64_t)attach->data.size, attach->data.data, attach->i_id));
01088
01089 if (!attach->data.data) {
01090
01091 pst_index_ll *ptr = pst_getID(pst, attach->i_id);
01092 if (!ptr) {
01093 DEBUG_WARN(("Couldn't find ID pointer. Cannot save attachment to file\n"));
01094 DEBUG_RET();
01095 return;
01096 }
01097 }
01098
01099 fprintf(f_output, "\n--%s\n", boundary);
01100 if (!attach->mimetype.str) {
01101 fprintf(f_output, "Content-Type: %s\n", MIME_TYPE_DEFAULT);
01102 } else {
01103 fprintf(f_output, "Content-Type: %s\n", attach->mimetype.str);
01104 }
01105 fprintf(f_output, "Content-Transfer-Encoding: base64\n");
01106
01107 if (attach->filename2.str) {
01108
01109
01110 pst_rfc2231(&attach->filename2);
01111 fprintf(f_output, "Content-Disposition: attachment; \n filename*=%s\n\n", attach->filename2.str);
01112 }
01113 else if (attach->filename1.str) {
01114
01115 fprintf(f_output, "Content-Disposition: attachment; filename=\"%s\"\n\n", attach->filename1.str);
01116 }
01117 else {
01118
01119 fprintf(f_output, "Content-Disposition: inline\n\n");
01120 }
01121
01122 (void)pst_attach_to_file_base64(pst, attach, f_output);
01123 fprintf(f_output, "\n\n");
01124 DEBUG_RET();
01125 }
01126
01127
01128 int valid_headers(char *header)
01129 {
01130
01131
01132
01133
01134
01135 if (header) {
01136 if ((strncasecmp(header, "X-Barracuda-URL: ", 17) == 0) ||
01137 (strncasecmp(header, "X-ASG-Debug-ID: ", 16) == 0) ||
01138 (strncasecmp(header, "Return-Path: ", 13) == 0) ||
01139 (strncasecmp(header, "Received: ", 10) == 0) ||
01140 (strncasecmp(header, "Subject: ", 9) == 0) ||
01141 (strncasecmp(header, "Date: ", 6) == 0) ||
01142 (strncasecmp(header, "From: ", 6) == 0) ||
01143 (strncasecmp(header, "X-x: ", 5) == 0) ||
01144 (strncasecmp(header, "Microsoft Mail Internet Headers", 31) == 0)) {
01145 return 1;
01146 }
01147 else {
01148 if (strlen(header) > 2) {
01149 DEBUG_INFO(("Ignore bogus headers = %s\n", header));
01150 }
01151 return 0;
01152 }
01153 }
01154 else return 0;
01155 }
01156
01157
01158 void header_has_field(char *header, char *field, int *flag)
01159 {
01160 DEBUG_ENT("header_has_field");
01161 if (my_stristr(header, field) || (strncasecmp(header, field+1, strlen(field)-1) == 0)) {
01162 DEBUG_INFO(("header block has %s header\n", field+1));
01163 *flag = 1;
01164 }
01165 DEBUG_RET();
01166 }
01167
01168
01169 void header_get_subfield(char *field, const char *subfield, char *body_subfield, size_t size_subfield)
01170 {
01171 if (!field) return;
01172 DEBUG_ENT("header_get_subfield");
01173 char search[60];
01174 snprintf(search, sizeof(search), " %s=", subfield);
01175 field++;
01176 char *n = header_end_field(field);
01177 char *s = my_stristr(field, search);
01178 if (n && s && (s < n)) {
01179 char *e, *f, save;
01180 s += strlen(search);
01181 if (*s == '"') {
01182 s++;
01183 e = strchr(s, '"');
01184 }
01185 else {
01186 e = strchr(s, ';');
01187 f = strchr(s, '\n');
01188 if (e && f && (f < e)) e = f;
01189 }
01190 if (!e || (e > n)) e = n;
01191 save = *e;
01192 *e = '\0';
01193 snprintf(body_subfield, size_subfield, "%s", s);
01194 *e = save;
01195 DEBUG_INFO(("body %s %s from headers\n", subfield, body_subfield));
01196 }
01197 DEBUG_RET();
01198 }
01199
01200 char* header_get_field(char *header, char *field)
01201 {
01202 char *t = my_stristr(header, field);
01203 if (!t && (strncasecmp(header, field+1, strlen(field)-1) == 0)) t = header;
01204 return t;
01205 }
01206
01207
01208
01209
01210 char *header_end_field(char *field)
01211 {
01212 char *e = strchr(field+1, '\n');
01213 while (e && ((e[1] == ' ') || (e[1] == '\t'))) {
01214 e = strchr(e+1, '\n');
01215 }
01216 return e;
01217 }
01218
01219
01220 void header_strip_field(char *header, char *field)
01221 {
01222 char *t = header_get_field(header, field);
01223 if (t) {
01224 char *e = header_end_field(t);
01225 if (e) {
01226 if (t == header) e++;
01227 while (*e != '\0') {
01228 *t = *e;
01229 t++;
01230 e++;
01231 }
01232 *t = '\0';
01233 }
01234 else {
01235
01236 *t = '\0';
01237 }
01238 }
01239 }
01240
01241
01242 int test_base64(char *body)
01243 {
01244 int b64 = 0;
01245 uint8_t *b = (uint8_t *)body;
01246 DEBUG_ENT("test_base64");
01247 while (*b) {
01248 if ((*b < 32) && (*b != 9) && (*b != 10)) {
01249 DEBUG_INFO(("found base64 byte %d\n", (int)*b));
01250 DEBUG_HEXDUMPC(body, strlen(body), 0x10);
01251 b64 = 1;
01252 break;
01253 }
01254 b++;
01255 }
01256 DEBUG_RET();
01257 return b64;
01258 }
01259
01260
01261 void find_html_charset(char *html, char *charset, size_t charsetlen)
01262 {
01263 const int index = 1;
01264 const int nmatch = index+1;
01265 regmatch_t match[nmatch];
01266 DEBUG_ENT("find_html_charset");
01267 int rc = regexec(&meta_charset_pattern, html, nmatch, match, 0);
01268 if (rc == 0) {
01269 int s = match[index].rm_so;
01270 int e = match[index].rm_eo;
01271 if (s != -1) {
01272 char save = html[e];
01273 html[e] = '\0';
01274 snprintf(charset, charsetlen, "%s", html+s);
01275 html[e] = save;
01276 DEBUG_INFO(("charset %s from html text\n", charset));
01277 }
01278 else {
01279 DEBUG_INFO(("matching %d %d %d %d\n", match[0].rm_so, match[0].rm_eo, match[1].rm_so, match[1].rm_eo));
01280 DEBUG_HEXDUMPC(html, strlen(html), 0x10);
01281 }
01282 }
01283 else {
01284 DEBUG_INFO(("regexec returns %d\n", rc));
01285 }
01286 DEBUG_RET();
01287 }
01288
01289
01290 void find_rfc822_headers(char** extra_mime_headers)
01291 {
01292 DEBUG_ENT("find_rfc822_headers");
01293 char *headers = *extra_mime_headers;
01294 if (headers) {
01295 char *temp, *t;
01296 while ((temp = strstr(headers, "\n\n"))) {
01297 temp[1] = '\0';
01298 t = header_get_field(headers, "\nContent-Type: ");
01299 if (t) {
01300 t++;
01301 DEBUG_INFO(("found content type header\n"));
01302 char *n = strchr(t, '\n');
01303 char *s = strstr(t, ": ");
01304 char *e = strchr(t, ';');
01305 if (!e || (e > n)) e = n;
01306 if (s && (s < e)) {
01307 s += 2;
01308 if (!strncasecmp(s, RFC822, e-s)) {
01309 headers = temp+2;
01310 DEBUG_INFO(("found 822 headers\n%s\n", headers));
01311 break;
01312 }
01313 }
01314 }
01315
01316 headers = temp+2;
01317 }
01318 *extra_mime_headers = headers;
01319 }
01320 DEBUG_RET();
01321 }
01322
01323
01324 void write_body_part(FILE* f_output, pst_string *body, char *mime, char *charset, char *boundary, pst_file* pst)
01325 {
01326 DEBUG_ENT("write_body_part");
01327 if (body->is_utf8 && (strcasecmp("utf-8", charset))) {
01328
01329
01330
01331 size_t rc;
01332 DEBUG_INFO(("Convert %s utf-8 to %s\n", mime, charset));
01333 pst_vbuf *newer = pst_vballoc(2);
01334 rc = pst_vb_utf8to8bit(newer, body->str, strlen(body->str), charset);
01335 if (rc == (size_t)-1) {
01336
01337 free(newer->b);
01338 DEBUG_INFO(("Failed to convert %s utf-8 to %s\n", mime, charset));
01339 charset = "utf-8";
01340 }
01341 else {
01342
01343 pst_vbgrow(newer, 1);
01344 newer->b[newer->dlen] = '\0';
01345 free(body->str);
01346 body->str = newer->b;
01347 }
01348 free(newer);
01349 }
01350 removeCR(body->str);
01351 int base64 = test_base64(body->str);
01352 fprintf(f_output, "\n--%s\n", boundary);
01353 fprintf(f_output, "Content-Type: %s; charset=\"%s\"\n", mime, charset);
01354 if (base64) fprintf(f_output, "Content-Transfer-Encoding: base64\n");
01355 fprintf(f_output, "\n");
01356 if (base64) {
01357 char *enc = pst_base64_encode(body->str, strlen(body->str));
01358 if (enc) {
01359 write_email_body(f_output, enc);
01360 fprintf(f_output, "\n");
01361 free(enc);
01362 }
01363 }
01364 else {
01365 write_email_body(f_output, body->str);
01366 }
01367 DEBUG_RET();
01368 }
01369
01370
01371 void write_schedule_part_data(FILE* f_output, pst_item* item, const char* sender, const char* method)
01372 {
01373 fprintf(f_output, "BEGIN:VCALENDAR\n");
01374 fprintf(f_output, "VERSION:2.0\n");
01375 fprintf(f_output, "PRODID:LibPST v%s\n", VERSION);
01376 if (method) fprintf(f_output, "METHOD:%s\n", method);
01377 fprintf(f_output, "BEGIN:VEVENT\n");
01378 if (sender) {
01379 if (item->email->outlook_sender_name.str) {
01380 fprintf(f_output, "ORGANIZER;CN=\"%s\":MAILTO:%s\n", item->email->outlook_sender_name.str, sender);
01381 } else {
01382 fprintf(f_output, "ORGANIZER;CN=\"\":MAILTO:%s\n", sender);
01383 }
01384 }
01385 write_appointment(f_output, item);
01386 fprintf(f_output, "END:VCALENDAR\n");
01387 }
01388
01389
01390 void write_schedule_part(FILE* f_output, pst_item* item, const char* sender, const char* boundary)
01391 {
01392 const char* method = "REQUEST";
01393 const char* charset = "utf-8";
01394 char fname[30];
01395 if (!item->appointment) return;
01396
01397
01398 fprintf(f_output, "\n--%s\n", boundary);
01399 fprintf(f_output, "Content-Type: %s; method=\"%s\"; charset=\"%s\"\n\n", "text/calendar", method, charset);
01400 write_schedule_part_data(f_output, item, sender, method);
01401 fprintf(f_output, "\n");
01402
01403
01404 snprintf(fname, sizeof(fname), "i%i.ics", rand());
01405 fprintf(f_output, "\n--%s\n", boundary);
01406 fprintf(f_output, "Content-Type: %s; charset=\"%s\"; name=\"%s\"\n", "text/calendar", "utf-8", fname);
01407 fprintf(f_output, "Content-Disposition: attachment; filename=\"%s\"\n\n", fname);
01408 write_schedule_part_data(f_output, item, sender, method);
01409 fprintf(f_output, "\n");
01410 }
01411
01412
01413 void write_normal_email(FILE* f_output, char f_name[], pst_item* item, int mode, int mode_MH, pst_file* pst, int save_rtf, char** extra_mime_headers)
01414 {
01415 char boundary[60];
01416 char altboundary[66];
01417 char *altboundaryp = NULL;
01418 char body_charset[30];
01419 char buffer_charset[30];
01420 char body_report[60];
01421 char sender[60];
01422 int sender_known = 0;
01423 char *temp = NULL;
01424 time_t em_time;
01425 char *c_time;
01426 char *headers = NULL;
01427 int has_from, has_subject, has_to, has_cc, has_date, has_msgid;
01428 has_from = has_subject = has_to = has_cc = has_date = has_msgid = 0;
01429 DEBUG_ENT("write_normal_email");
01430
01431 pst_convert_utf8_null(item, &item->email->header);
01432 headers = valid_headers(item->email->header.str) ? item->email->header.str :
01433 valid_headers(*extra_mime_headers) ? *extra_mime_headers :
01434 NULL;
01435
01436
01437 strncpy(body_charset, pst_default_charset(item, sizeof(buffer_charset), buffer_charset), sizeof(body_charset));
01438 body_charset[sizeof(body_charset)-1] = '\0';
01439 strncpy(body_report, "delivery-status", sizeof(body_report));
01440 body_report[sizeof(body_report)-1] = '\0';
01441
01442
01443 pst_convert_utf8(item, &item->email->sender_address);
01444 if (item->email->sender_address.str && strchr(item->email->sender_address.str, '@')) {
01445 temp = item->email->sender_address.str;
01446 sender_known = 1;
01447 }
01448 else {
01449 temp = "MAILER-DAEMON";
01450 }
01451 strncpy(sender, temp, sizeof(sender));
01452 sender[sizeof(sender)-1] = '\0';
01453
01454
01455 if (item->email->sent_date) {
01456 em_time = pst_fileTimeToUnixTime(item->email->sent_date);
01457 c_time = ctime(&em_time);
01458 if (c_time)
01459 c_time[strlen(c_time)-1] = '\0';
01460 else
01461 c_time = "Fri Dec 28 12:06:21 2001";
01462 } else
01463 c_time = "Fri Dec 28 12:06:21 2001";
01464
01465
01466 snprintf(boundary, sizeof(boundary), "--boundary-LibPST-iamunique-%i_-_-", rand());
01467 snprintf(altboundary, sizeof(altboundary), "alt-%s", boundary);
01468
01469
01470 if (headers ) {
01471 char *t;
01472 removeCR(headers);
01473
01474 temp = strstr(headers, "\n\n");
01475 if (temp) {
01476
01477 temp[1] = '\0';
01478
01479
01480
01481 if (!*extra_mime_headers) *extra_mime_headers = temp+2;
01482 DEBUG_INFO(("Found extra mime headers\n%s\n", temp+2));
01483 }
01484
01485
01486 header_has_field(headers, "\nFrom: ", &has_from);
01487 header_has_field(headers, "\nTo: ", &has_to);
01488 header_has_field(headers, "\nSubject: ", &has_subject);
01489 header_has_field(headers, "\nDate: ", &has_date);
01490 header_has_field(headers, "\nCC: ", &has_cc);
01491 header_has_field(headers, "\nMessage-Id: ", &has_msgid);
01492
01493
01494 t = header_get_field(headers, "\nContent-Type: ");
01495 header_get_subfield(t, "charset", body_charset, sizeof(body_charset));
01496 header_get_subfield(t, "report-type", body_report, sizeof(body_report));
01497
01498
01499 if (!sender_known) {
01500 t = header_get_field(headers, "\nFrom: ");
01501 if (t) {
01502
01503 t++;
01504 char *n = strchr(t, '\n');
01505 char *s = strchr(t, '<');
01506 char *e = strchr(t, '>');
01507 if (s && e && n && (s < e) && (e < n)) {
01508 char save = *e;
01509 *e = '\0';
01510 snprintf(sender, sizeof(sender), "%s", s+1);
01511 *e = save;
01512 }
01513 }
01514 }
01515
01516
01517 header_strip_field(headers, "\nMicrosoft Mail Internet Headers");
01518 header_strip_field(headers, "\nMIME-Version: ");
01519 header_strip_field(headers, "\nContent-Type: ");
01520 header_strip_field(headers, "\nContent-Transfer-Encoding: ");
01521 header_strip_field(headers, "\nContent-class: ");
01522 header_strip_field(headers, "\nX-MimeOLE: ");
01523 header_strip_field(headers, "\nBcc:");
01524 header_strip_field(headers, "\nX-From_: ");
01525 }
01526
01527 DEBUG_INFO(("About to print Header\n"));
01528
01529 if (item && item->subject.str) {
01530 pst_convert_utf8(item, &item->subject);
01531 DEBUG_INFO(("item->subject = %s\n", item->subject.str));
01532 }
01533
01534 if (mode != MODE_SEPARATE) {
01535
01536
01537
01538
01539 fprintf(f_output, "From \"%s\" %s\n", sender, c_time);
01540 }
01541
01542
01543 if (headers) {
01544 int len = strlen(headers);
01545 if (len > 0) {
01546 fprintf(f_output, "%s", headers);
01547
01548 if (headers[len-1] != '\n') fprintf(f_output, "\n");
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561 }
01562 }
01563
01564
01565 if ((item->flags & PST_FLAG_READ) == PST_FLAG_READ) {
01566 fprintf(f_output, "Status: RO\n");
01567 }
01568
01569
01570
01571 if (!has_from) {
01572 if (item->email->outlook_sender_name.str){
01573 pst_rfc2047(item, &item->email->outlook_sender_name, 1);
01574 fprintf(f_output, "From: %s <%s>\n", item->email->outlook_sender_name.str, sender);
01575 } else {
01576 fprintf(f_output, "From: <%s>\n", sender);
01577 }
01578 }
01579
01580 if (!has_subject) {
01581 if (item->subject.str) {
01582 pst_rfc2047(item, &item->subject, 0);
01583 fprintf(f_output, "Subject: %s\n", item->subject.str);
01584 } else {
01585 fprintf(f_output, "Subject: \n");
01586 }
01587 }
01588
01589 if (!has_to && item->email->sentto_address.str) {
01590 pst_rfc2047(item, &item->email->sentto_address, 0);
01591 fprintf(f_output, "To: %s\n", item->email->sentto_address.str);
01592 }
01593
01594 if (!has_cc && item->email->cc_address.str) {
01595 pst_rfc2047(item, &item->email->cc_address, 0);
01596 fprintf(f_output, "Cc: %s\n", item->email->cc_address.str);
01597 }
01598
01599 if (!has_date && item->email->sent_date) {
01600 char c_time[C_TIME_SIZE];
01601 struct tm stm;
01602 gmtime_r(&em_time, &stm);
01603 strftime(c_time, C_TIME_SIZE, "%a, %d %b %Y %H:%M:%S %z", &stm);
01604 fprintf(f_output, "Date: %s\n", c_time);
01605 }
01606
01607 if (!has_msgid && item->email->messageid.str) {
01608 pst_convert_utf8(item, &item->email->messageid);
01609 fprintf(f_output, "Message-Id: %s\n", item->email->messageid.str);
01610 }
01611
01612
01613
01614 pst_convert_utf8_null(item, &item->email->sender_address);
01615 if (item->email->sender_address.str && !strchr(item->email->sender_address.str, '@')
01616 && strcmp(item->email->sender_address.str, ".")
01617 && (strlen(item->email->sender_address.str) > 0)) {
01618 fprintf(f_output, "X-libpst-forensic-sender: %s\n", item->email->sender_address.str);
01619 }
01620
01621 if (item->email->bcc_address.str) {
01622 pst_convert_utf8(item, &item->email->bcc_address);
01623 fprintf(f_output, "X-libpst-forensic-bcc: %s\n", item->email->bcc_address.str);
01624 }
01625
01626
01627 fprintf(f_output, "MIME-Version: 1.0\n");
01628 if (item->type == PST_TYPE_REPORT) {
01629
01630 fprintf(f_output, "Content-Type: multipart/report; report-type=%s;\n\tboundary=\"%s\"\n", body_report, boundary);
01631 }
01632 else {
01633 fprintf(f_output, "Content-Type: multipart/mixed;\n\tboundary=\"%s\"\n", boundary);
01634 }
01635 fprintf(f_output, "\n");
01636
01637
01638 if ((item->type == PST_TYPE_REPORT) && (item->email->report_text.str)) {
01639 write_body_part(f_output, &item->email->report_text, "text/plain", body_charset, boundary, pst);
01640 fprintf(f_output, "\n");
01641 }
01642
01643 if (item->body.str && item->email->htmlbody.str) {
01644
01645 fprintf(f_output, "\n--%s\n", boundary);
01646 fprintf(f_output, "Content-Type: multipart/alternative;\n\tboundary=\"%s\"\n", altboundary);
01647 altboundaryp = altboundary;
01648 }
01649 else {
01650 altboundaryp = boundary;
01651 }
01652
01653 if (item->body.str) {
01654 write_body_part(f_output, &item->body, "text/plain", body_charset, altboundaryp, pst);
01655 }
01656
01657 if (item->email->htmlbody.str) {
01658 find_html_charset(item->email->htmlbody.str, body_charset, sizeof(body_charset));
01659 write_body_part(f_output, &item->email->htmlbody, "text/html", body_charset, altboundaryp, pst);
01660 }
01661
01662 if (item->body.str && item->email->htmlbody.str) {
01663
01664 fprintf(f_output, "\n--%s--\n", altboundary);
01665 }
01666
01667 if (item->email->rtf_compressed.data && save_rtf) {
01668 pst_item_attach* attach = (pst_item_attach*)pst_malloc(sizeof(pst_item_attach));
01669 DEBUG_INFO(("Adding RTF body as attachment\n"));
01670 memset(attach, 0, sizeof(pst_item_attach));
01671 attach->next = item->attach;
01672 item->attach = attach;
01673 attach->data.data = pst_lzfu_decompress(item->email->rtf_compressed.data, item->email->rtf_compressed.size, &attach->data.size);
01674 attach->filename2.str = strdup(RTF_ATTACH_NAME);
01675 attach->filename2.is_utf8 = 1;
01676 attach->mimetype.str = strdup(RTF_ATTACH_TYPE);
01677 attach->mimetype.is_utf8 = 1;
01678 }
01679
01680 if (item->email->encrypted_body.data) {
01681 pst_item_attach* attach = (pst_item_attach*)pst_malloc(sizeof(pst_item_attach));
01682 DEBUG_INFO(("Adding encrypted text body as attachment\n"));
01683 attach = (pst_item_attach*) pst_malloc(sizeof(pst_item_attach));
01684 memset(attach, 0, sizeof(pst_item_attach));
01685 attach->next = item->attach;
01686 item->attach = attach;
01687 attach->data.data = item->email->encrypted_body.data;
01688 attach->data.size = item->email->encrypted_body.size;
01689 item->email->encrypted_body.data = NULL;
01690 }
01691
01692 if (item->email->encrypted_htmlbody.data) {
01693 pst_item_attach* attach = (pst_item_attach*)pst_malloc(sizeof(pst_item_attach));
01694 DEBUG_INFO(("Adding encrypted HTML body as attachment\n"));
01695 attach = (pst_item_attach*) pst_malloc(sizeof(pst_item_attach));
01696 memset(attach, 0, sizeof(pst_item_attach));
01697 attach->next = item->attach;
01698 item->attach = attach;
01699 attach->data.data = item->email->encrypted_htmlbody.data;
01700 attach->data.size = item->email->encrypted_htmlbody.size;
01701 item->email->encrypted_htmlbody.data = NULL;
01702 }
01703
01704 if (item->type == PST_TYPE_SCHEDULE) {
01705 write_schedule_part(f_output, item, sender, boundary);
01706 }
01707
01708
01709 {
01710 pst_item_attach* attach;
01711 int attach_num = 0;
01712 for (attach = item->attach; attach; attach = attach->next) {
01713 pst_convert_utf8_null(item, &attach->filename1);
01714 pst_convert_utf8_null(item, &attach->filename2);
01715 pst_convert_utf8_null(item, &attach->mimetype);
01716 DEBUG_INFO(("Attempting Attachment encoding\n"));
01717 if (attach->method == PST_ATTACH_EMBEDDED) {
01718 DEBUG_INFO(("have an embedded rfc822 message attachment\n"));
01719 if (attach->mimetype.str) {
01720 DEBUG_INFO(("which already has a mime-type of %s\n", attach->mimetype.str));
01721 free(attach->mimetype.str);
01722 }
01723 attach->mimetype.str = strdup(RFC822);
01724 attach->mimetype.is_utf8 = 1;
01725 find_rfc822_headers(extra_mime_headers);
01726 write_embedded_message(f_output, attach, boundary, pst, extra_mime_headers);
01727 }
01728 else if (attach->data.data || attach->i_id) {
01729 if (mode == MODE_SEPARATE && !mode_MH)
01730 write_separate_attachment(f_name, attach, ++attach_num, pst);
01731 else
01732 write_inline_attachment(f_output, attach, boundary, pst);
01733 }
01734 }
01735 }
01736
01737 fprintf(f_output, "\n--%s--\n\n", boundary);
01738 DEBUG_RET();
01739 }
01740
01741
01742 void write_vcard(FILE* f_output, pst_item* item, pst_item_contact* contact, char comment[])
01743 {
01744 char* result = NULL;
01745 size_t resultlen = 0;
01746 char time_buffer[30];
01747
01748
01749
01750
01751 DEBUG_ENT("write_vcard");
01752
01753
01754 pst_convert_utf8_null(item, &contact->fullname);
01755 pst_convert_utf8_null(item, &contact->surname);
01756 pst_convert_utf8_null(item, &contact->first_name);
01757 pst_convert_utf8_null(item, &contact->middle_name);
01758 pst_convert_utf8_null(item, &contact->display_name_prefix);
01759 pst_convert_utf8_null(item, &contact->suffix);
01760 pst_convert_utf8_null(item, &contact->nickname);
01761 pst_convert_utf8_null(item, &contact->address1);
01762 pst_convert_utf8_null(item, &contact->address2);
01763 pst_convert_utf8_null(item, &contact->address3);
01764 pst_convert_utf8_null(item, &contact->home_po_box);
01765 pst_convert_utf8_null(item, &contact->home_street);
01766 pst_convert_utf8_null(item, &contact->home_city);
01767 pst_convert_utf8_null(item, &contact->home_state);
01768 pst_convert_utf8_null(item, &contact->home_postal_code);
01769 pst_convert_utf8_null(item, &contact->home_country);
01770 pst_convert_utf8_null(item, &contact->home_address);
01771 pst_convert_utf8_null(item, &contact->business_po_box);
01772 pst_convert_utf8_null(item, &contact->business_street);
01773 pst_convert_utf8_null(item, &contact->business_city);
01774 pst_convert_utf8_null(item, &contact->business_state);
01775 pst_convert_utf8_null(item, &contact->business_postal_code);
01776 pst_convert_utf8_null(item, &contact->business_country);
01777 pst_convert_utf8_null(item, &contact->business_address);
01778 pst_convert_utf8_null(item, &contact->other_po_box);
01779 pst_convert_utf8_null(item, &contact->other_street);
01780 pst_convert_utf8_null(item, &contact->other_city);
01781 pst_convert_utf8_null(item, &contact->other_state);
01782 pst_convert_utf8_null(item, &contact->other_postal_code);
01783 pst_convert_utf8_null(item, &contact->other_country);
01784 pst_convert_utf8_null(item, &contact->other_address);
01785 pst_convert_utf8_null(item, &contact->business_fax);
01786 pst_convert_utf8_null(item, &contact->business_phone);
01787 pst_convert_utf8_null(item, &contact->business_phone2);
01788 pst_convert_utf8_null(item, &contact->car_phone);
01789 pst_convert_utf8_null(item, &contact->home_fax);
01790 pst_convert_utf8_null(item, &contact->home_phone);
01791 pst_convert_utf8_null(item, &contact->home_phone2);
01792 pst_convert_utf8_null(item, &contact->isdn_phone);
01793 pst_convert_utf8_null(item, &contact->mobile_phone);
01794 pst_convert_utf8_null(item, &contact->other_phone);
01795 pst_convert_utf8_null(item, &contact->pager_phone);
01796 pst_convert_utf8_null(item, &contact->primary_fax);
01797 pst_convert_utf8_null(item, &contact->primary_phone);
01798 pst_convert_utf8_null(item, &contact->radio_phone);
01799 pst_convert_utf8_null(item, &contact->telex);
01800 pst_convert_utf8_null(item, &contact->job_title);
01801 pst_convert_utf8_null(item, &contact->profession);
01802 pst_convert_utf8_null(item, &contact->assistant_name);
01803 pst_convert_utf8_null(item, &contact->assistant_phone);
01804 pst_convert_utf8_null(item, &contact->company_name);
01805 pst_convert_utf8_null(item, &item->body);
01806
01807
01808 fprintf(f_output, "BEGIN:VCARD\n");
01809 fprintf(f_output, "FN:%s\n", pst_rfc2426_escape(contact->fullname.str, &result, &resultlen));
01810
01811
01812 fprintf(f_output, "N:%s;", (!contact->surname.str) ? "" : pst_rfc2426_escape(contact->surname.str, &result, &resultlen));
01813 fprintf(f_output, "%s;", (!contact->first_name.str) ? "" : pst_rfc2426_escape(contact->first_name.str, &result, &resultlen));
01814 fprintf(f_output, "%s;", (!contact->middle_name.str) ? "" : pst_rfc2426_escape(contact->middle_name.str, &result, &resultlen));
01815 fprintf(f_output, "%s;", (!contact->display_name_prefix.str) ? "" : pst_rfc2426_escape(contact->display_name_prefix.str, &result, &resultlen));
01816 fprintf(f_output, "%s\n", (!contact->suffix.str) ? "" : pst_rfc2426_escape(contact->suffix.str, &result, &resultlen));
01817
01818 if (contact->nickname.str)
01819 fprintf(f_output, "NICKNAME:%s\n", pst_rfc2426_escape(contact->nickname.str, &result, &resultlen));
01820 if (contact->address1.str)
01821 fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address1.str, &result, &resultlen));
01822 if (contact->address2.str)
01823 fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address2.str, &result, &resultlen));
01824 if (contact->address3.str)
01825 fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address3.str, &result, &resultlen));
01826 if (contact->birthday)
01827 fprintf(f_output, "BDAY:%s\n", pst_rfc2425_datetime_format(contact->birthday, sizeof(time_buffer), time_buffer));
01828
01829 if (contact->home_address.str) {
01830
01831 fprintf(f_output, "ADR;TYPE=home:%s;", (!contact->home_po_box.str) ? "" : pst_rfc2426_escape(contact->home_po_box.str, &result, &resultlen));
01832 fprintf(f_output, "%s;", "");
01833 fprintf(f_output, "%s;", (!contact->home_street.str) ? "" : pst_rfc2426_escape(contact->home_street.str, &result, &resultlen));
01834 fprintf(f_output, "%s;", (!contact->home_city.str) ? "" : pst_rfc2426_escape(contact->home_city.str, &result, &resultlen));
01835 fprintf(f_output, "%s;", (!contact->home_state.str) ? "" : pst_rfc2426_escape(contact->home_state.str, &result, &resultlen));
01836 fprintf(f_output, "%s;", (!contact->home_postal_code.str) ? "" : pst_rfc2426_escape(contact->home_postal_code.str, &result, &resultlen));
01837 fprintf(f_output, "%s\n", (!contact->home_country.str) ? "" : pst_rfc2426_escape(contact->home_country.str, &result, &resultlen));
01838 fprintf(f_output, "LABEL;TYPE=home:%s\n", pst_rfc2426_escape(contact->home_address.str, &result, &resultlen));
01839 }
01840
01841 if (contact->business_address.str) {
01842
01843 fprintf(f_output, "ADR;TYPE=work:%s;", (!contact->business_po_box.str) ? "" : pst_rfc2426_escape(contact->business_po_box.str, &result, &resultlen));
01844 fprintf(f_output, "%s;", "");
01845 fprintf(f_output, "%s;", (!contact->business_street.str) ? "" : pst_rfc2426_escape(contact->business_street.str, &result, &resultlen));
01846 fprintf(f_output, "%s;", (!contact->business_city.str) ? "" : pst_rfc2426_escape(contact->business_city.str, &result, &resultlen));
01847 fprintf(f_output, "%s;", (!contact->business_state.str) ? "" : pst_rfc2426_escape(contact->business_state.str, &result, &resultlen));
01848 fprintf(f_output, "%s;", (!contact->business_postal_code.str) ? "" : pst_rfc2426_escape(contact->business_postal_code.str, &result, &resultlen));
01849 fprintf(f_output, "%s\n", (!contact->business_country.str) ? "" : pst_rfc2426_escape(contact->business_country.str, &result, &resultlen));
01850 fprintf(f_output, "LABEL;TYPE=work:%s\n", pst_rfc2426_escape(contact->business_address.str, &result, &resultlen));
01851 }
01852
01853 if (contact->other_address.str) {
01854
01855 fprintf(f_output, "ADR;TYPE=postal:%s;",(!contact->other_po_box.str) ? "" : pst_rfc2426_escape(contact->other_po_box.str, &result, &resultlen));
01856 fprintf(f_output, "%s;", "");
01857 fprintf(f_output, "%s;", (!contact->other_street.str) ? "" : pst_rfc2426_escape(contact->other_street.str, &result, &resultlen));
01858 fprintf(f_output, "%s;", (!contact->other_city.str) ? "" : pst_rfc2426_escape(contact->other_city.str, &result, &resultlen));
01859 fprintf(f_output, "%s;", (!contact->other_state.str) ? "" : pst_rfc2426_escape(contact->other_state.str, &result, &resultlen));
01860 fprintf(f_output, "%s;", (!contact->other_postal_code.str) ? "" : pst_rfc2426_escape(contact->other_postal_code.str, &result, &resultlen));
01861 fprintf(f_output, "%s\n", (!contact->other_country.str) ? "" : pst_rfc2426_escape(contact->other_country.str, &result, &resultlen));
01862 fprintf(f_output, "LABEL;TYPE=postal:%s\n", pst_rfc2426_escape(contact->other_address.str, &result, &resultlen));
01863 }
01864
01865 if (contact->business_fax.str) fprintf(f_output, "TEL;TYPE=work,fax:%s\n", pst_rfc2426_escape(contact->business_fax.str, &result, &resultlen));
01866 if (contact->business_phone.str) fprintf(f_output, "TEL;TYPE=work,voice:%s\n", pst_rfc2426_escape(contact->business_phone.str, &result, &resultlen));
01867 if (contact->business_phone2.str) fprintf(f_output, "TEL;TYPE=work,voice:%s\n", pst_rfc2426_escape(contact->business_phone2.str, &result, &resultlen));
01868 if (contact->car_phone.str) fprintf(f_output, "TEL;TYPE=car,voice:%s\n", pst_rfc2426_escape(contact->car_phone.str, &result, &resultlen));
01869 if (contact->home_fax.str) fprintf(f_output, "TEL;TYPE=home,fax:%s\n", pst_rfc2426_escape(contact->home_fax.str, &result, &resultlen));
01870 if (contact->home_phone.str) fprintf(f_output, "TEL;TYPE=home,voice:%s\n", pst_rfc2426_escape(contact->home_phone.str, &result, &resultlen));
01871 if (contact->home_phone2.str) fprintf(f_output, "TEL;TYPE=home,voice:%s\n", pst_rfc2426_escape(contact->home_phone2.str, &result, &resultlen));
01872 if (contact->isdn_phone.str) fprintf(f_output, "TEL;TYPE=isdn:%s\n", pst_rfc2426_escape(contact->isdn_phone.str, &result, &resultlen));
01873 if (contact->mobile_phone.str) fprintf(f_output, "TEL;TYPE=cell,voice:%s\n", pst_rfc2426_escape(contact->mobile_phone.str, &result, &resultlen));
01874 if (contact->other_phone.str) fprintf(f_output, "TEL;TYPE=msg:%s\n", pst_rfc2426_escape(contact->other_phone.str, &result, &resultlen));
01875 if (contact->pager_phone.str) fprintf(f_output, "TEL;TYPE=pager:%s\n", pst_rfc2426_escape(contact->pager_phone.str, &result, &resultlen));
01876 if (contact->primary_fax.str) fprintf(f_output, "TEL;TYPE=fax,pref:%s\n", pst_rfc2426_escape(contact->primary_fax.str, &result, &resultlen));
01877 if (contact->primary_phone.str) fprintf(f_output, "TEL;TYPE=phone,pref:%s\n", pst_rfc2426_escape(contact->primary_phone.str, &result, &resultlen));
01878 if (contact->radio_phone.str) fprintf(f_output, "TEL;TYPE=pcs:%s\n", pst_rfc2426_escape(contact->radio_phone.str, &result, &resultlen));
01879 if (contact->telex.str) fprintf(f_output, "TEL;TYPE=bbs:%s\n", pst_rfc2426_escape(contact->telex.str, &result, &resultlen));
01880 if (contact->job_title.str) fprintf(f_output, "TITLE:%s\n", pst_rfc2426_escape(contact->job_title.str, &result, &resultlen));
01881 if (contact->profession.str) fprintf(f_output, "ROLE:%s\n", pst_rfc2426_escape(contact->profession.str, &result, &resultlen));
01882 if (contact->assistant_name.str || contact->assistant_phone.str) {
01883 fprintf(f_output, "AGENT:BEGIN:VCARD\n");
01884 if (contact->assistant_name.str) fprintf(f_output, "FN:%s\n", pst_rfc2426_escape(contact->assistant_name.str, &result, &resultlen));
01885 if (contact->assistant_phone.str) fprintf(f_output, "TEL:%s\n", pst_rfc2426_escape(contact->assistant_phone.str, &result, &resultlen));
01886 }
01887 if (contact->company_name.str) fprintf(f_output, "ORG:%s\n", pst_rfc2426_escape(contact->company_name.str, &result, &resultlen));
01888 if (comment) fprintf(f_output, "NOTE:%s\n", pst_rfc2426_escape(comment, &result, &resultlen));
01889 if (item->body.str) fprintf(f_output, "NOTE:%s\n", pst_rfc2426_escape(item->body.str, &result, &resultlen));
01890
01891 write_extra_categories(f_output, item);
01892
01893 fprintf(f_output, "VERSION: 3.0\n");
01894 fprintf(f_output, "END:VCARD\n\n");
01895 if (result) free(result);
01896 DEBUG_RET();
01897 }
01898
01899
01907 int write_extra_categories(FILE* f_output, pst_item* item)
01908 {
01909 char* result = NULL;
01910 size_t resultlen = 0;
01911 pst_item_extra_field *ef = item->extra_fields;
01912 const char *fmt = "CATEGORIES:%s";
01913 int category_started = 0;
01914 while (ef) {
01915 if (strcmp(ef->field_name, "Keywords") == 0) {
01916 fprintf(f_output, fmt, pst_rfc2426_escape(ef->value, &result, &resultlen));
01917 fmt = ", %s";
01918 category_started = 1;
01919 }
01920 ef = ef->next;
01921 }
01922 if (category_started) fprintf(f_output, "\n");
01923 if (result) free(result);
01924 return category_started;
01925 }
01926
01927
01928 void write_journal(FILE* f_output, pst_item* item)
01929 {
01930 char* result = NULL;
01931 size_t resultlen = 0;
01932 char time_buffer[30];
01933 pst_item_journal* journal = item->journal;
01934
01935
01936 pst_convert_utf8_null(item, &item->subject);
01937 pst_convert_utf8_null(item, &item->body);
01938
01939 fprintf(f_output, "BEGIN:VJOURNAL\n");
01940 fprintf(f_output, "DTSTAMP:%s\n", pst_rfc2445_datetime_format_now(sizeof(time_buffer), time_buffer));
01941 if (item->create_date)
01942 fprintf(f_output, "CREATED:%s\n", pst_rfc2445_datetime_format(item->create_date, sizeof(time_buffer), time_buffer));
01943 if (item->modify_date)
01944 fprintf(f_output, "LAST-MOD:%s\n", pst_rfc2445_datetime_format(item->modify_date, sizeof(time_buffer), time_buffer));
01945 if (item->subject.str)
01946 fprintf(f_output, "SUMMARY:%s\n", pst_rfc2426_escape(item->subject.str, &result, &resultlen));
01947 if (item->body.str)
01948 fprintf(f_output, "DESCRIPTION:%s\n", pst_rfc2426_escape(item->body.str, &result, &resultlen));
01949 if (journal && journal->start)
01950 fprintf(f_output, "DTSTART;VALUE=DATE-TIME:%s\n", pst_rfc2445_datetime_format(journal->start, sizeof(time_buffer), time_buffer));
01951 fprintf(f_output, "END:VJOURNAL\n");
01952 if (result) free(result);
01953 }
01954
01955
01956 void write_appointment(FILE* f_output, pst_item* item)
01957 {
01958 char* result = NULL;
01959 size_t resultlen = 0;
01960 char time_buffer[30];
01961 pst_item_appointment* appointment = item->appointment;
01962
01963
01964 pst_convert_utf8_null(item, &item->subject);
01965 pst_convert_utf8_null(item, &item->body);
01966 pst_convert_utf8_null(item, &appointment->location);
01967
01968 fprintf(f_output, "DTSTAMP:%s\n", pst_rfc2445_datetime_format_now(sizeof(time_buffer), time_buffer));
01969 if (item->create_date)
01970 fprintf(f_output, "CREATED:%s\n", pst_rfc2445_datetime_format(item->create_date, sizeof(time_buffer), time_buffer));
01971 if (item->modify_date)
01972 fprintf(f_output, "LAST-MOD:%s\n", pst_rfc2445_datetime_format(item->modify_date, sizeof(time_buffer), time_buffer));
01973 if (item->subject.str)
01974 fprintf(f_output, "SUMMARY:%s\n", pst_rfc2426_escape(item->subject.str, &result, &resultlen));
01975 if (item->body.str)
01976 fprintf(f_output, "DESCRIPTION:%s\n", pst_rfc2426_escape(item->body.str, &result, &resultlen));
01977 if (appointment && appointment->start)
01978 fprintf(f_output, "DTSTART;VALUE=DATE-TIME:%s\n", pst_rfc2445_datetime_format(appointment->start, sizeof(time_buffer), time_buffer));
01979 if (appointment && appointment->end)
01980 fprintf(f_output, "DTEND;VALUE=DATE-TIME:%s\n", pst_rfc2445_datetime_format(appointment->end, sizeof(time_buffer), time_buffer));
01981 if (appointment && appointment->location.str)
01982 fprintf(f_output, "LOCATION:%s\n", pst_rfc2426_escape(appointment->location.str, &result, &resultlen));
01983 if (appointment) {
01984 switch (appointment->showas) {
01985 case PST_FREEBUSY_TENTATIVE:
01986 fprintf(f_output, "STATUS:TENTATIVE\n");
01987 break;
01988 case PST_FREEBUSY_FREE:
01989
01990 fprintf(f_output, "TRANSP:TRANSPARENT\n");
01991 case PST_FREEBUSY_BUSY:
01992 case PST_FREEBUSY_OUT_OF_OFFICE:
01993 fprintf(f_output, "STATUS:CONFIRMED\n");
01994 break;
01995 }
01996 if (appointment->is_recurring) {
01997 const char* rules[] = {"DAILY", "WEEKLY", "MONTHLY", "YEARLY"};
01998 const char* days[] = {"SU", "MO", "TU", "WE", "TH", "FR", "SA"};
01999 pst_recurrence *rdata = pst_convert_recurrence(appointment);
02000 fprintf(f_output, "RRULE:FREQ=%s", rules[rdata->type]);
02001 if (rdata->count) fprintf(f_output, ";COUNT=%u", rdata->count);
02002 if ((rdata->interval != 1) &&
02003 (rdata->interval)) fprintf(f_output, ";INTERVAL=%u", rdata->interval);
02004 if (rdata->dayofmonth) fprintf(f_output, ";BYMONTHDAY=%d", rdata->dayofmonth);
02005 if (rdata->monthofyear) fprintf(f_output, ";BYMONTH=%d", rdata->monthofyear);
02006 if (rdata->position) fprintf(f_output, ";BYSETPOS=%d", rdata->position);
02007 if (rdata->bydaymask) {
02008 char byday[40];
02009 int empty = 1;
02010 int i=0;
02011 memset(byday, 0, sizeof(byday));
02012 for (i=0; i<6; i++) {
02013 int bit = 1 << i;
02014 if (bit & rdata->bydaymask) {
02015 char temp[40];
02016 snprintf(temp, sizeof(temp), "%s%s%s", byday, (empty) ? ";BYDAY=" : ";", days[i]);
02017 strcpy(byday, temp);
02018 empty = 0;
02019 }
02020 }
02021 fprintf(f_output, "%s", byday);
02022 }
02023 fprintf(f_output, "\n");
02024 pst_free_recurrence(rdata);
02025 }
02026 switch (appointment->label) {
02027 case PST_APP_LABEL_NONE:
02028 if (!write_extra_categories(f_output, item)) fprintf(f_output, "CATEGORIES:NONE\n");
02029 break;
02030 case PST_APP_LABEL_IMPORTANT:
02031 fprintf(f_output, "CATEGORIES:IMPORTANT\n");
02032 break;
02033 case PST_APP_LABEL_BUSINESS:
02034 fprintf(f_output, "CATEGORIES:BUSINESS\n");
02035 break;
02036 case PST_APP_LABEL_PERSONAL:
02037 fprintf(f_output, "CATEGORIES:PERSONAL\n");
02038 break;
02039 case PST_APP_LABEL_VACATION:
02040 fprintf(f_output, "CATEGORIES:VACATION\n");
02041 break;
02042 case PST_APP_LABEL_MUST_ATTEND:
02043 fprintf(f_output, "CATEGORIES:MUST-ATTEND\n");
02044 break;
02045 case PST_APP_LABEL_TRAVEL_REQ:
02046 fprintf(f_output, "CATEGORIES:TRAVEL-REQUIRED\n");
02047 break;
02048 case PST_APP_LABEL_NEEDS_PREP:
02049 fprintf(f_output, "CATEGORIES:NEEDS-PREPARATION\n");
02050 break;
02051 case PST_APP_LABEL_BIRTHDAY:
02052 fprintf(f_output, "CATEGORIES:BIRTHDAY\n");
02053 break;
02054 case PST_APP_LABEL_ANNIVERSARY:
02055 fprintf(f_output, "CATEGORIES:ANNIVERSARY\n");
02056 break;
02057 case PST_APP_LABEL_PHONE_CALL:
02058 fprintf(f_output, "CATEGORIES:PHONE-CALL\n");
02059 break;
02060 }
02061 }
02062 fprintf(f_output, "END:VEVENT\n");
02063 if (result) free(result);
02064 }
02065
02066
02067 void create_enter_dir(struct file_ll* f, pst_item *item)
02068 {
02069 pst_convert_utf8(item, &item->file_as);
02070 f->type = item->type;
02071 f->stored_count = (item->folder) ? item->folder->item_count : 0;
02072
02073 DEBUG_ENT("create_enter_dir");
02074 if (mode == MODE_KMAIL)
02075 f->name = mk_kmail_dir(item->file_as.str);
02076 else if (mode == MODE_RECURSE) {
02077 f->name = mk_recurse_dir(item->file_as.str, f->type);
02078 if (mode_thunder) {
02079 FILE *type_file = fopen(".type", "w");
02080 fprintf(type_file, "%d\n", item->type);
02081 fclose(type_file);
02082 }
02083 } else if (mode == MODE_SEPARATE) {
02084
02085 mk_separate_dir(item->file_as.str);
02086 f->name = (char*) pst_malloc(file_name_len);
02087 memset(f->name, 0, file_name_len);
02088 } else {
02089 f->name = (char*) pst_malloc(strlen(item->file_as.str)+strlen(OUTPUT_TEMPLATE)+1);
02090 sprintf(f->name, OUTPUT_TEMPLATE, item->file_as.str);
02091 }
02092
02093 f->dname = (char*) pst_malloc(strlen(item->file_as.str)+1);
02094 strcpy(f->dname, item->file_as.str);
02095
02096 if (overwrite != 1) {
02097 int x = 0;
02098 char *temp = (char*) pst_malloc (strlen(f->name)+10);
02099
02100 sprintf(temp, "%s", f->name);
02101 check_filename(temp);
02102 while ((f->output = fopen(temp, "r"))) {
02103 DEBUG_INFO(("need to increase filename because one already exists with that name\n"));
02104 DEBUG_INFO(("- increasing it to %s%d\n", f->name, x));
02105 x++;
02106 sprintf(temp, "%s%08d", f->name, x);
02107 DEBUG_INFO(("- trying \"%s\"\n", f->name));
02108 if (x == 99999999) {
02109 DIE(("create_enter_dir: Why can I not create a folder %s? I have tried %i extensions...\n", f->name, x));
02110 }
02111 fclose(f->output);
02112 }
02113 if (x > 0) {
02114 free (f->name);
02115 f->name = temp;
02116 } else {
02117 free(temp);
02118 }
02119 }
02120
02121 DEBUG_INFO(("f->name = %s\nitem->folder_name = %s\n", f->name, item->file_as.str));
02122 if (mode != MODE_SEPARATE) {
02123 check_filename(f->name);
02124 if (!(f->output = fopen(f->name, "w"))) {
02125 DIE(("create_enter_dir: Could not open file \"%s\" for write\n", f->name));
02126 }
02127 }
02128 DEBUG_RET();
02129 }
02130
02131
02132 void close_enter_dir(struct file_ll *f)
02133 {
02134 DEBUG_INFO(("processed item count for folder %s is %i, skipped %i, total %i \n",
02135 f->dname, f->item_count, f->skip_count, f->stored_count));
02136 if (output_mode != OUTPUT_QUIET) {
02137 pst_debug_lock();
02138 printf("\t\"%s\" - %i items done, %i items skipped.\n", f->dname, f->item_count, f->skip_count);
02139 fflush(stdout);
02140 pst_debug_unlock();
02141 }
02142 if (f->output) {
02143 if (mode == MODE_SEPARATE) DEBUG_WARN(("close_enter_dir finds open separate file\n"));
02144 struct stat st;
02145 fclose(f->output);
02146 stat(f->name, &st);
02147 if (!st.st_size) {
02148 DEBUG_WARN(("removing empty output file %s\n", f->name));
02149 remove(f->name);
02150 }
02151 f->output = NULL;
02152 }
02153 free(f->name);
02154 free(f->dname);
02155
02156 if (mode == MODE_KMAIL)
02157 close_kmail_dir();
02158 else if (mode == MODE_RECURSE) {
02159 if (mode_thunder) {
02160 FILE *type_file = fopen(".size", "w");
02161 fprintf(type_file, "%i %i\n", f->item_count, f->stored_count);
02162 fclose(type_file);
02163 }
02164 close_recurse_dir();
02165 } else if (mode == MODE_SEPARATE)
02166 close_separate_dir();
02167 }
02168