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