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"
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 email_count;
00025 int32_t skip_count;
00026 int32_t type;
00027 };
00028
00029 void process(pst_item *outeritem, pst_desc_ll *d_ptr);
00030 void write_email_body(FILE *f, char *body);
00031 void removeCR(char *c);
00032 void usage();
00033 void version();
00034 char* mk_kmail_dir(char*);
00035 int close_kmail_dir();
00036 char* mk_recurse_dir(char*);
00037 int close_recurse_dir();
00038 char* mk_separate_dir(char *dir);
00039 int close_separate_dir();
00040 int mk_separate_file(struct file_ll *f);
00041 char* my_stristr(char *haystack, char *needle);
00042 void check_filename(char *fname);
00043 void write_separate_attachment(char f_name[], pst_item_attach* attach, int attach_num, pst_file* pst);
00044 void write_embedded_message(FILE* f_output, pst_item_attach* attach, char *boundary, pst_file* pf, char** extra_mime_headers);
00045 void write_inline_attachment(FILE* f_output, pst_item_attach* attach, char *boundary, pst_file* pst);
00046 void header_has_field(char *header, char *field, int *flag);
00047 void header_get_subfield(char *field, const char *subfield, char *body_subfield, size_t size_subfield);
00048 char* header_get_field(char *header, char *field);
00049 char* header_end_field(char *field);
00050 void header_strip_field(char *header, char *field);
00051 int test_base64(char *body);
00052 void find_html_charset(char *html, char *charset, size_t charsetlen);
00053 void find_rfc822_headers(char** extra_mime_headers);
00054 void write_body_part(FILE* f_output, char *body, int32_t body_was_unicode, char *mime, char *charset, char *boundary, pst_file* pst);
00055 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);
00056 void write_vcard(FILE* f_output, pst_item_contact* contact, char comment[]);
00057 void write_appointment(FILE* f_output, pst_item_appointment* appointment,
00058 pst_item_email* email, FILETIME* create_date, FILETIME* modify_date);
00059 void create_enter_dir(struct file_ll* f, pst_item *item);
00060 void close_enter_dir(struct file_ll *f);
00061
00062 const char* prog_name;
00063 char* output_dir = ".";
00064 char* kmail_chdir = NULL;
00065
00066
00067
00068 #define MODE_NORMAL 0
00069
00070
00071
00072 #define MODE_KMAIL 1
00073
00074
00075
00076 #define MODE_RECURSE 2
00077
00078
00079
00080
00081 #define MODE_SEPARATE 3
00082
00083
00084 #define MODE_DECSPEW 4
00085
00086
00087
00088 #define OUTPUT_NORMAL 0
00089
00090
00091 #define OUTPUT_QUIET 1
00092
00093
00094 #define MIME_TYPE_DEFAULT "application/octet-stream"
00095 #define RFC822 "message/rfc822"
00096
00097
00098 #define CMODE_VCARD 0
00099 #define CMODE_LIST 1
00100
00101
00102 #define DMODE_EXCLUDE 0
00103 #define DMODE_INCLUDE 1
00104
00105
00106
00107 #define RTF_ATTACH_NAME "rtf-body.rtf"
00108
00109 #define RTF_ATTACH_TYPE "application/rtf"
00110
00111
00112 int mode = MODE_NORMAL;
00113 int mode_MH = 0;
00114 int output_mode = OUTPUT_NORMAL;
00115 int contact_mode = CMODE_VCARD;
00116 int deleted_mode = DMODE_EXCLUDE;
00117 int overwrite = 0;
00118 int save_rtf_body = 1;
00119 pst_file pstfile;
00120 regex_t meta_charset_pattern;
00121
00122
00123 void process(pst_item *outeritem, pst_desc_ll *d_ptr)
00124 {
00125 struct file_ll ff;
00126 pst_item *item = NULL;
00127
00128 DEBUG_ENT("process");
00129 memset(&ff, 0, sizeof(ff));
00130 create_enter_dir(&ff, outeritem);
00131
00132 while (d_ptr) {
00133 DEBUG_MAIN(("main: New item record\n"));
00134 if (!d_ptr->desc) {
00135 DEBUG_WARN(("main: ERROR ?? item's desc record is NULL\n"));
00136 ff.skip_count++;
00137 }
00138 else {
00139 DEBUG_MAIN(("main: Desc Email ID %#"PRIx64" [d_ptr->id = %#"PRIx64"]\n", d_ptr->desc->id, d_ptr->id));
00140
00141 item = pst_parse_item(&pstfile, d_ptr, NULL);
00142 DEBUG_MAIN(("main: About to process item\n"));
00143 if (item && item->email && item->email->subject && item->email->subject->subj) {
00144 DEBUG_EMAIL(("item->email->subject->subj = %s\n", item->email->subject->subj));
00145 }
00146 if (item) {
00147 if (item->folder && d_ptr->child && (deleted_mode == DMODE_INCLUDE || strcasecmp(item->file_as, "Deleted Items"))) {
00148
00149 if (output_mode != OUTPUT_QUIET) printf("Processing Folder \"%s\"\n", item->file_as);
00150 process(item, d_ptr->child);
00151
00152 } else if (item->contact && (item->type == PST_TYPE_CONTACT)) {
00153
00154
00155
00156 if (mode == MODE_SEPARATE) mk_separate_file(&ff);
00157 ff.email_count++;
00158 DEBUG_MAIN(("main: Processing Contact\n"));
00159 if (ff.type != PST_TYPE_CONTACT) {
00160 DEBUG_MAIN(("main: I have a contact, but the folder isn't a contacts folder. Processing anyway\n"));
00161 }
00162 if (contact_mode == CMODE_VCARD)
00163 write_vcard(ff.output, item->contact, item->comment);
00164 else
00165 fprintf(ff.output, "%s <%s>\n", item->contact->fullname, item->contact->address1);
00166
00167 } else if (item->email && (item->type == PST_TYPE_NOTE || item->type == PST_TYPE_REPORT || item->type == PST_TYPE_OTHER)) {
00168 char *extra_mime_headers = NULL;
00169 if (mode == MODE_SEPARATE) mk_separate_file(&ff);
00170 ff.email_count++;
00171 DEBUG_MAIN(("main: Processing Email\n"));
00172 if ((ff.type != PST_TYPE_NOTE) && (ff.type != PST_TYPE_REPORT) && (ff.type != PST_TYPE_OTHER)) {
00173 DEBUG_MAIN(("main: I have an email, but the folder isn't an email folder. Processing anyway\n"));
00174 }
00175 write_normal_email(ff.output, ff.name, item, mode, mode_MH, &pstfile, save_rtf_body, &extra_mime_headers);
00176
00177 } else if (item->journal && (item->type == PST_TYPE_JOURNAL)) {
00178
00179 if (mode == MODE_SEPARATE) mk_separate_file(&ff);
00180 ff.email_count++;
00181 DEBUG_MAIN(("main: Processing Journal Entry\n"));
00182 if (ff.type != PST_TYPE_JOURNAL) {
00183 DEBUG_MAIN(("main: I have a journal entry, but the folder isn't a journal folder. Processing anyway\n"));
00184 }
00185 fprintf(ff.output, "BEGIN:VJOURNAL\n");
00186 if (item->email && item->email->subject && item->email->subject->subj)
00187 fprintf(ff.output, "SUMMARY:%s\n", pst_rfc2426_escape(item->email->subject->subj));
00188 if (item->email && item->email->body)
00189 fprintf(ff.output, "DESCRIPTION:%s\n", pst_rfc2426_escape(item->email->body));
00190 if (item->journal->start)
00191 fprintf(ff.output, "DTSTART;VALUE=DATE-TIME:%s\n", pst_rfc2445_datetime_format(item->journal->start));
00192 fprintf(ff.output, "END:VJOURNAL\n\n");
00193
00194 } else if (item->appointment && (item->type == PST_TYPE_APPOINTMENT)) {
00195
00196 if (mode == MODE_SEPARATE) mk_separate_file(&ff);
00197 ff.email_count++;
00198 DEBUG_MAIN(("main: Processing Appointment Entry\n"));
00199 if (ff.type != PST_TYPE_APPOINTMENT) {
00200 DEBUG_MAIN(("main: I have an appointment, but folder isn't specified as an appointment type. Processing...\n"));
00201 }
00202 write_appointment(ff.output, item->appointment, item->email, item->create_date, item->modify_date);
00203
00204 } else if (item->message_store) {
00205
00206 DEBUG_MAIN(("item with message store content, type %i %s folder type %i, skipping it\n", item->type, item->ascii_type, ff.type));
00207
00208 } else {
00209
00210
00211 DEBUG_MAIN(("main: Unknown item type %i (%s) name (%s)\n",
00212 item->type, item->ascii_type, item->file_as));
00213 }
00214 pst_freeItem(item);
00215 } else {
00216 ff.skip_count++;
00217 DEBUG_MAIN(("main: A NULL item was seen\n"));
00218 }
00219 d_ptr = d_ptr->next;
00220 }
00221 }
00222 close_enter_dir(&ff);
00223 DEBUG_RET();
00224 }
00225
00226
00227
00228 int main(int argc, char* const* argv) {
00229 pst_item *item = NULL;
00230 pst_desc_ll *d_ptr;
00231 char * fname = NULL;
00232 char *d_log = NULL;
00233 int c,x;
00234 char *temp = NULL;
00235 prog_name = argv[0];
00236
00237 time_t now = time(NULL);
00238 srand((unsigned)now);
00239
00240 if (regcomp(&meta_charset_pattern, "<meta[^>]*content=\"[^>]*charset=([^>\";]*)[\";]", REG_ICASE | REG_EXTENDED)) {
00241 printf("cannot compile regex pattern to find content charset in html bodies\n");
00242 exit(3);
00243 }
00244
00245
00246 while ((c = getopt(argc, argv, "bCc:Dd:hko:qrSMVw"))!= -1) {
00247 switch (c) {
00248 case 'b':
00249 save_rtf_body = 0;
00250 break;
00251 case 'C':
00252 mode = MODE_DECSPEW;
00253 break;
00254 case 'c':
00255 if (optarg && optarg[0]=='v')
00256 contact_mode=CMODE_VCARD;
00257 else if (optarg && optarg[0]=='l')
00258 contact_mode=CMODE_LIST;
00259 else {
00260 usage();
00261 exit(0);
00262 }
00263 break;
00264 case 'D':
00265 deleted_mode = DMODE_INCLUDE;
00266 break;
00267 case 'd':
00268 d_log = optarg;
00269 break;
00270 case 'h':
00271 usage();
00272 exit(0);
00273 break;
00274 case 'V':
00275 version();
00276 exit(0);
00277 break;
00278 case 'k':
00279 mode = MODE_KMAIL;
00280 break;
00281 case 'M':
00282 mode = MODE_SEPARATE;
00283 mode_MH = 1;
00284 break;
00285 case 'o':
00286 output_dir = optarg;
00287 break;
00288 case 'q':
00289 output_mode = OUTPUT_QUIET;
00290 break;
00291 case 'r':
00292 mode = MODE_RECURSE;
00293 break;
00294 case 'S':
00295 mode = MODE_SEPARATE;
00296 break;
00297 case 'w':
00298 overwrite = 1;
00299 break;
00300 default:
00301 usage();
00302 exit(1);
00303 break;
00304 }
00305 }
00306
00307 if (argc > optind) {
00308 fname = argv[optind];
00309 } else {
00310 usage();
00311 exit(2);
00312 }
00313
00314 #ifdef DEBUG_ALL
00315
00316 if (!d_log) d_log = "readpst.log";
00317 #endif // defined DEBUG_ALL
00318 DEBUG_INIT(d_log);
00319 DEBUG_REGISTER_CLOSE();
00320 DEBUG_ENT("main");
00321
00322 if (mode == MODE_DECSPEW) {
00323 FILE *fp;
00324 char buf[1024];
00325 size_t l = 0;
00326 if (NULL == (fp = fopen(fname, "rb"))) {
00327 fprintf(stderr, "Couldn't open file %s\n", fname );
00328 DEBUG_RET();
00329 return 1;
00330 }
00331
00332 while (0 != (l = fread(buf, 1, 1024, fp))) {
00333 if (0 != pst_decrypt(0, buf, l, PST_COMP_ENCRYPT))
00334 fprintf(stderr, "pst_decrypt() failed (I'll try to continue)\n");
00335
00336 if (l != pst_fwrite(buf, 1, l, stdout)) {
00337 fprintf(stderr, "Couldn't output to stdout?\n");
00338 DEBUG_RET();
00339 return 1;
00340 }
00341 }
00342 DEBUG_RET();
00343 return 0;
00344 }
00345
00346 if (output_mode != OUTPUT_QUIET) printf("Opening PST file and indexes...\n");
00347
00348 RET_DERROR(pst_open(&pstfile, fname), 1, ("Error opening File\n"));
00349 RET_DERROR(pst_load_index(&pstfile), 2, ("Index Error\n"));
00350
00351 pst_load_extended_attributes(&pstfile);
00352
00353 if (chdir(output_dir)) {
00354 x = errno;
00355 pst_close(&pstfile);
00356 DEBUG_RET();
00357 DIE(("main: Cannot change to output dir %s: %s\n", output_dir, strerror(x)));
00358 }
00359
00360 if (output_mode != OUTPUT_QUIET) printf("About to start processing first record...\n");
00361
00362 d_ptr = pstfile.d_head;
00363 item = pst_parse_item(&pstfile, d_ptr, NULL);
00364 if (!item || !item->message_store) {
00365 DEBUG_RET();
00366 DIE(("main: Could not get root record\n"));
00367 }
00368
00369
00370 if (!item->file_as) {
00371 if (!(temp = strrchr(fname, '/')))
00372 if (!(temp = strrchr(fname, '\\')))
00373 temp = fname;
00374 else
00375 temp++;
00376 else
00377 temp++;
00378 item->file_as = (char*)xmalloc(strlen(temp)+1);
00379 strcpy(item->file_as, temp);
00380 DEBUG_MAIN(("file_as was blank, so am using %s\n", item->file_as));
00381 }
00382 DEBUG_MAIN(("main: Root Folder Name: %s\n", item->file_as));
00383
00384 d_ptr = pst_getTopOfFolders(&pstfile, item);
00385 if (!d_ptr) {
00386 DEBUG_RET();
00387 DIE(("Top of folders record not found. Cannot continue\n"));
00388 }
00389
00390 process(item, d_ptr->child);
00391 pst_freeItem(item);
00392 pst_close(&pstfile);
00393 DEBUG_RET();
00394 regfree(&meta_charset_pattern);
00395 return 0;
00396 }
00397
00398
00399 void write_email_body(FILE *f, char *body) {
00400 char *n = body;
00401
00402 DEBUG_ENT("write_email_body");
00403 while (n) {
00404 if (strncmp(body, "From ", 5) == 0)
00405 fprintf(f, ">");
00406 if ((n = strchr(body, '\n'))) {
00407 n++;
00408 pst_fwrite(body, n-body, 1, f);
00409 body = n;
00410 }
00411 }
00412 pst_fwrite(body, strlen(body), 1, f);
00413 DEBUG_RET();
00414 }
00415
00416
00417 void removeCR (char *c) {
00418
00419 char *a, *b;
00420 DEBUG_ENT("removeCR");
00421 a = b = c;
00422 while (*a != '\0') {
00423 *b = *a;
00424 if (*a != '\r') b++;
00425 a++;
00426 }
00427 *b = '\0';
00428 DEBUG_RET();
00429 }
00430
00431
00432 void usage() {
00433 DEBUG_ENT("usage");
00434 version();
00435 printf("Usage: %s [OPTIONS] {PST FILENAME}\n", prog_name);
00436 printf("OPTIONS:\n");
00437 printf("\t-V\t- Version. Display program version\n");
00438 printf("\t-C\t- Decrypt (compressible encryption) the entire file and output on stdout (not typically useful)\n");
00439 printf("\t-D\t- Include deleted items in output\n");
00440 printf("\t-M\t- MH. Write emails in the MH format\n");
00441 printf("\t-S\t- Separate. Write emails in the separate format\n");
00442 printf("\t-b\t- Don't save RTF-Body attachments\n");
00443 printf("\t-c[v|l]\t- Set the Contact output mode. -cv = VCard, -cl = EMail list\n");
00444 printf("\t-d <filename> \t- Debug to file. This is a binary log. Use readpstlog to print it\n");
00445 printf("\t-h\t- Help. This screen\n");
00446 printf("\t-k\t- KMail. Output in kmail format\n");
00447 printf("\t-o <dirname>\t- Output directory to write files to. CWD is changed *after* opening pst file\n");
00448 printf("\t-q\t- Quiet. Only print error messages\n");
00449 printf("\t-r\t- Recursive. Output in a recursive format\n");
00450 printf("\t-w\t- Overwrite any output mbox files\n");
00451 DEBUG_RET();
00452 }
00453
00454
00455 void version() {
00456 DEBUG_ENT("version");
00457 printf("ReadPST / LibPST v%s\n", VERSION);
00458 #if BYTE_ORDER == BIG_ENDIAN
00459 printf("Big Endian implementation being used.\n");
00460 #elif BYTE_ORDER == LITTLE_ENDIAN
00461 printf("Little Endian implementation being used.\n");
00462 #else
00463 # error "Byte order not supported by this library"
00464 #endif
00465 #ifdef __GNUC__
00466 printf("GCC %d.%d : %s %s\n", __GNUC__, __GNUC_MINOR__, __DATE__, __TIME__);
00467 #endif
00468 DEBUG_RET();
00469 }
00470
00471
00472 char *mk_kmail_dir(char *fname) {
00473
00474
00475
00476
00477 char *dir, *out_name, *index;
00478 int x;
00479 DEBUG_ENT("mk_kmail_dir");
00480 if (kmail_chdir && chdir(kmail_chdir)) {
00481 x = errno;
00482 DIE(("mk_kmail_dir: Cannot change to directory %s: %s\n", kmail_chdir, strerror(x)));
00483 }
00484 dir = malloc(strlen(fname)+strlen(OUTPUT_KMAIL_DIR_TEMPLATE)+1);
00485 sprintf(dir, OUTPUT_KMAIL_DIR_TEMPLATE, fname);
00486 check_filename(dir);
00487 if (D_MKDIR(dir)) {
00488
00489 if (errno != EEXIST) {
00490 x = errno;
00491 DIE(("mk_kmail_dir: Cannot create directory %s: %s\n", dir, strerror(x)));
00492 }
00493 }
00494 kmail_chdir = realloc(kmail_chdir, strlen(dir)+1);
00495 strcpy(kmail_chdir, dir);
00496 free (dir);
00497
00498
00499 index = malloc(strlen(fname)+strlen(KMAIL_INDEX)+1);
00500 sprintf(index, KMAIL_INDEX, fname);
00501 unlink(index);
00502 free(index);
00503
00504 out_name = malloc(strlen(fname)+strlen(OUTPUT_TEMPLATE)+1);
00505 sprintf(out_name, OUTPUT_TEMPLATE, fname);
00506 DEBUG_RET();
00507 return out_name;
00508 }
00509
00510
00511 int close_kmail_dir() {
00512
00513 int x;
00514 DEBUG_ENT("close_kmail_dir");
00515 if (kmail_chdir) {
00516 free(kmail_chdir);
00517 kmail_chdir = NULL;
00518 } else {
00519 if (chdir("..")) {
00520 x = errno;
00521 DIE(("close_kmail_dir: Cannot move up dir (..): %s\n", strerror(x)));
00522 }
00523 }
00524 DEBUG_RET();
00525 return 0;
00526 }
00527
00528
00529
00530
00531
00532 char *mk_recurse_dir(char *dir) {
00533 int x;
00534 char *out_name;
00535 DEBUG_ENT("mk_recurse_dir");
00536 check_filename(dir);
00537 if (D_MKDIR (dir)) {
00538 if (errno != EEXIST) {
00539 x = errno;
00540 DIE(("mk_recurse_dir: Cannot create directory %s: %s\n", dir, strerror(x)));
00541 }
00542 }
00543 if (chdir (dir)) {
00544 x = errno;
00545 DIE(("mk_recurse_dir: Cannot change to directory %s: %s\n", dir, strerror(x)));
00546 }
00547 out_name = malloc(strlen("mbox")+1);
00548 strcpy(out_name, "mbox");
00549 DEBUG_RET();
00550 return out_name;
00551 }
00552
00553
00554 int close_recurse_dir() {
00555 int x;
00556 DEBUG_ENT("close_recurse_dir");
00557 if (chdir("..")) {
00558 x = errno;
00559 DIE(("close_recurse_dir: Cannot go up dir (..): %s\n", strerror(x)));
00560 }
00561 DEBUG_RET();
00562 return 0;
00563 }
00564
00565
00566 char *mk_separate_dir(char *dir) {
00567 size_t dirsize = strlen(dir) + 10;
00568 char dir_name[dirsize];
00569 int x = 0, y = 0;
00570
00571 DEBUG_ENT("mk_separate_dir");
00572 do {
00573 if (y == 0)
00574 snprintf(dir_name, dirsize, "%s", dir);
00575 else
00576 snprintf(dir_name, dirsize, "%s" SEP_MAIL_FILE_TEMPLATE, dir, y);
00577
00578 check_filename(dir_name);
00579 DEBUG_MAIN(("about to try creating %s\n", dir_name));
00580 if (D_MKDIR(dir_name)) {
00581 if (errno != EEXIST) {
00582 x = errno;
00583 DIE(("mk_separate_dir: Cannot create directory %s: %s\n", dir, strerror(x)));
00584 }
00585 } else {
00586 break;
00587 }
00588 y++;
00589 } while (overwrite == 0);
00590
00591 if (chdir(dir_name)) {
00592 x = errno;
00593 DIE(("mk_separate_dir: Cannot change to directory %s: %s\n", dir, strerror(x)));
00594 }
00595
00596 if (overwrite) {
00597
00598 #if !defined(WIN32) && !defined(__CYGWIN__)
00599 DIR * sdir = NULL;
00600 struct dirent *dirent = NULL;
00601 struct stat filestat;
00602 if (!(sdir = opendir("./"))) {
00603 WARN(("mk_separate_dir: Cannot open dir \"%s\" for deletion of old contents\n", "./"));
00604 } else {
00605 while ((dirent = readdir(sdir))) {
00606 if (lstat(dirent->d_name, &filestat) != -1)
00607 if (S_ISREG(filestat.st_mode)) {
00608 if (unlink(dirent->d_name)) {
00609 y = errno;
00610 DIE(("mk_separate_dir: unlink returned error on file %s: %s\n", dirent->d_name, strerror(y)));
00611 }
00612 }
00613 }
00614 }
00615 #endif
00616 }
00617
00618
00619 DEBUG_RET();
00620 return NULL;
00621 }
00622
00623
00624 int close_separate_dir() {
00625 int x;
00626 DEBUG_ENT("close_separate_dir");
00627 if (chdir("..")) {
00628 x = errno;
00629 DIE(("close_separate_dir: Cannot go up dir (..): %s\n", strerror(x)));
00630 }
00631 DEBUG_RET();
00632 return 0;
00633 }
00634
00635
00636 int mk_separate_file(struct file_ll *f) {
00637 const int name_offset = 1;
00638 DEBUG_ENT("mk_separate_file");
00639 DEBUG_MAIN(("opening next file to save email\n"));
00640 if (f->email_count > 999999999) {
00641 DIE(("mk_separate_file: The number of emails in this folder has become too high to handle"));
00642 }
00643 sprintf(f->name, SEP_MAIL_FILE_TEMPLATE, f->email_count + name_offset);
00644 if (f->output) fclose(f->output);
00645 f->output = NULL;
00646 check_filename(f->name);
00647 if (!(f->output = fopen(f->name, "w"))) {
00648 DIE(("mk_separate_file: Cannot open file to save email \"%s\"\n", f->name));
00649 }
00650 DEBUG_RET();
00651 return 0;
00652 }
00653
00654
00655 char *my_stristr(char *haystack, char *needle) {
00656
00657 char *x=haystack, *y=needle, *z = NULL;
00658 if (!haystack || !needle) {
00659 return NULL;
00660 }
00661 while (*y != '\0' && *x != '\0') {
00662 if (tolower(*y) == tolower(*x)) {
00663
00664 y++;
00665 if (!z) {
00666 z = x;
00667 }
00668 } else {
00669 y = needle;
00670 z = NULL;
00671 }
00672 x++;
00673 }
00674
00675 if (*y != '\0') return NULL;
00676 return z;
00677 }
00678
00679
00680 void check_filename(char *fname) {
00681 char *t = fname;
00682 DEBUG_ENT("check_filename");
00683 if (!t) {
00684 DEBUG_RET();
00685 return;
00686 }
00687 while ((t = strpbrk(t, "/\\:"))) {
00688
00689 *t = '_';
00690 }
00691 DEBUG_RET();
00692 }
00693
00694
00695 void write_separate_attachment(char f_name[], pst_item_attach* attach, int attach_num, pst_file* pst)
00696 {
00697 FILE *fp = NULL;
00698 int x = 0;
00699 char *temp = NULL;
00700
00701
00702
00703 char *attach_filename = (attach->filename2) ? attach->filename2
00704 : attach->filename1;
00705 DEBUG_ENT("write_separate_attachment");
00706
00707 check_filename(f_name);
00708 if (!attach_filename) {
00709
00710 temp = xmalloc(strlen(f_name)+15);
00711 sprintf(temp, "%s-attach%i", f_name, attach_num);
00712 } else {
00713
00714 temp = xmalloc(strlen(f_name)+strlen(attach_filename)+15);
00715 do {
00716 if (fp) fclose(fp);
00717 if (x == 0)
00718 sprintf(temp, "%s-%s", f_name, attach_filename);
00719 else
00720 sprintf(temp, "%s-%s-%i", f_name, attach_filename, x);
00721 } while ((fp = fopen(temp, "r")) && ++x < 99999999);
00722 if (x > 99999999) {
00723 DIE(("error finding attachment name. exhausted possibilities to %s\n", temp));
00724 }
00725 }
00726 DEBUG_EMAIL(("Saving attachment to %s\n", temp));
00727 if (!(fp = fopen(temp, "w"))) {
00728 WARN(("write_separate_attachment: Cannot open attachment save file \"%s\"\n", temp));
00729 } else {
00730 if (attach->data)
00731 pst_fwrite(attach->data, 1, attach->size, fp);
00732 else {
00733 (void)pst_attach_to_file(pst, attach, fp);
00734 }
00735 fclose(fp);
00736 }
00737 if (temp) free(temp);
00738 DEBUG_RET();
00739 }
00740
00741
00742 void write_embedded_message(FILE* f_output, pst_item_attach* attach, char *boundary, pst_file* pf, char** extra_mime_headers)
00743 {
00744 pst_index_ll *ptr;
00745 DEBUG_ENT("write_embedded_message");
00746 fprintf(f_output, "\n--%s\n", boundary);
00747 fprintf(f_output, "Content-Type: %s\n\n", attach->mimetype);
00748 ptr = pst_getID(pf, attach->id_val);
00749
00750 pst_desc_ll d_ptr;
00751 d_ptr.id = ptr->id;
00752 d_ptr.parent_id = 0;
00753 d_ptr.list_index = NULL;
00754 d_ptr.desc = ptr;
00755 d_ptr.no_child = 0;
00756 d_ptr.prev = NULL;
00757 d_ptr.next = NULL;
00758 d_ptr.parent = NULL;
00759 d_ptr.child = NULL;
00760 d_ptr.child_tail = NULL;
00761
00762 pst_item *item = pst_parse_item(pf, &d_ptr, attach->id2_head);
00763 write_normal_email(f_output, "", item, MODE_NORMAL, 0, pf, 0, extra_mime_headers);
00764 pst_freeItem(item);
00765
00766 DEBUG_RET();
00767 }
00768
00769
00770 void write_inline_attachment(FILE* f_output, pst_item_attach* attach, char *boundary, pst_file* pst)
00771 {
00772 char *attach_filename;
00773 char *enc = NULL;
00774 DEBUG_ENT("write_inline_attachment");
00775 DEBUG_EMAIL(("Attachment Size is %i, pointer %p, id %d\n", attach->size, attach->data, attach->id_val));
00776 if (attach->data) {
00777 enc = base64_encode (attach->data, attach->size);
00778 if (!enc) {
00779 DEBUG_EMAIL(("ERROR base64_encode returned NULL. Must have failed\n"));
00780 DEBUG_RET();
00781 return;
00782 }
00783 }
00784 else {
00785
00786 pst_index_ll *ptr = pst_getID(pst, attach->id_val);
00787 if (!ptr) {
00788 DEBUG_WARN(("Couldn't find ID pointer. Cannot save attachment to file\n"));
00789 DEBUG_RET();
00790 return;
00791 }
00792 }
00793
00794 fprintf(f_output, "\n--%s\n", boundary);
00795 if (!attach->mimetype) {
00796 fprintf(f_output, "Content-Type: %s\n", MIME_TYPE_DEFAULT);
00797 } else {
00798 fprintf(f_output, "Content-Type: %s\n", attach->mimetype);
00799 }
00800 fprintf(f_output, "Content-Transfer-Encoding: base64\n");
00801
00802
00803
00804 attach_filename = (attach->filename2) ? attach->filename2 : attach->filename1;
00805 if (!attach_filename) {
00806 fprintf(f_output, "Content-Disposition: inline\n\n");
00807 } else {
00808 fprintf(f_output, "Content-Disposition: attachment; filename=\"%s\"\n\n", attach_filename);
00809 }
00810
00811 if (attach->data) {
00812 pst_fwrite(enc, 1, strlen(enc), f_output);
00813 DEBUG_EMAIL(("Attachment Size after encoding is %i\n", strlen(enc)));
00814 free(enc);
00815 } else {
00816 (void)pst_attach_to_file_base64(pst, attach, f_output);
00817 }
00818 fprintf(f_output, "\n\n");
00819 DEBUG_RET();
00820 }
00821
00822
00823 void header_has_field(char *header, char *field, int *flag)
00824 {
00825 DEBUG_ENT("header_has_field");
00826 if (my_stristr(header, field) || (strncasecmp(header, field+1, strlen(field)-1) == 0)) {
00827 DEBUG_EMAIL(("header block has %s header\n", field+1));
00828 *flag = 1;
00829 }
00830 DEBUG_RET();
00831 }
00832
00833
00834 void header_get_subfield(char *field, const char *subfield, char *body_subfield, size_t size_subfield)
00835 {
00836 if (!field) return;
00837 DEBUG_ENT("header_get_subfield");
00838 char search[60];
00839 snprintf(search, sizeof(search), " %s=", subfield);
00840 field++;
00841 char *n = header_end_field(field);
00842 char *s = my_stristr(field, search);
00843 if (n && s && (s < n)) {
00844 char *e, *f, save;
00845 s += strlen(search);
00846 if (*s == '"') {
00847 s++;
00848 e = strchr(s, '"');
00849 }
00850 else {
00851 e = strchr(s, ';');
00852 f = strchr(s, '\n');
00853 if (e && f && (f < e)) e = f;
00854 }
00855 if (!e || (e > n)) e = n;
00856 save = *e;
00857 *e = '\0';
00858 snprintf(body_subfield, size_subfield, "%s", s);
00859 *e = save;
00860 DEBUG_EMAIL(("body %s %s from headers\n", subfield, body_subfield));
00861 }
00862 DEBUG_RET();
00863 }
00864
00865 char* header_get_field(char *header, char *field)
00866 {
00867 char *t = my_stristr(header, field);
00868 if (!t && (strncasecmp(header, field+1, strlen(field)-1) == 0)) t = header;
00869 return t;
00870 }
00871
00872
00873
00874
00875 char *header_end_field(char *field)
00876 {
00877 char *e = strchr(field+1, '\n');
00878 while (e && ((e[1] == ' ') || (e[1] == '\t'))) {
00879 e = strchr(e+1, '\n');
00880 }
00881 return e;
00882 }
00883
00884
00885 void header_strip_field(char *header, char *field)
00886 {
00887 char *t = header_get_field(header, field);
00888 if (t) {
00889 char *e = header_end_field(t);
00890 if (e) {
00891 if (t == header) e++;
00892 while (*e != '\0') {
00893 *t = *e;
00894 t++;
00895 e++;
00896 }
00897 *t = '\0';
00898 }
00899 else {
00900
00901 *t = '\0';
00902 }
00903 }
00904 }
00905
00906
00907 int test_base64(char *body)
00908 {
00909 int b64 = 0;
00910 uint8_t *b = (uint8_t *)body;
00911 DEBUG_ENT("test_base64");
00912 while (*b != 0) {
00913 if ((*b < 32) && (*b != 9) && (*b != 10)) {
00914 DEBUG_EMAIL(("found base64 byte %d\n", (int)*b));
00915 DEBUG_HEXDUMPC(body, strlen(body), 0x10);
00916 b64 = 1;
00917 break;
00918 }
00919 b++;
00920 }
00921 DEBUG_RET();
00922 return b64;
00923 }
00924
00925
00926 void find_html_charset(char *html, char *charset, size_t charsetlen)
00927 {
00928 const int index = 1;
00929 const int nmatch = index+1;
00930 regmatch_t match[nmatch];
00931 DEBUG_ENT("find_html_charset");
00932 int rc = regexec(&meta_charset_pattern, html, nmatch, match, 0);
00933 if (rc == 0) {
00934 int s = match[index].rm_so;
00935 int e = match[index].rm_eo;
00936 if (s != -1) {
00937 char save = html[e];
00938 html[e] = '\0';
00939 snprintf(charset, charsetlen, "%s", html+s);
00940 html[e] = save;
00941 DEBUG_EMAIL(("charset %s from html text\n", charset));
00942 }
00943 else {
00944 DEBUG_EMAIL(("matching %d %d %d %d", match[0].rm_so, match[0].rm_eo, match[1].rm_so, match[1].rm_eo));
00945 DEBUG_HEXDUMPC(html, strlen(html), 0x10);
00946 }
00947 }
00948 else {
00949 DEBUG_EMAIL(("regexec returns %d\n", rc));
00950 }
00951 DEBUG_RET();
00952 }
00953
00954
00955 void find_rfc822_headers(char** extra_mime_headers)
00956 {
00957 DEBUG_ENT("find_rfc822_headers");
00958 char *headers = *extra_mime_headers;
00959 if (headers) {
00960 char *temp, *t;
00961 while ((temp = strstr(headers, "\n\n"))) {
00962 temp[1] = '\0';
00963 t = header_get_field(headers, "\nContent-Type: ");
00964 if (t) {
00965 t++;
00966 DEBUG_EMAIL(("found content type header\n"));
00967 char *n = strchr(t, '\n');
00968 char *s = strstr(t, ": ");
00969 char *e = strchr(t, ';');
00970 if (!e || (e > n)) e = n;
00971 if (s && (s < e)) {
00972 s += 2;
00973 if (!strncasecmp(s, RFC822, e-s)) {
00974 headers = temp+2;
00975 DEBUG_EMAIL(("found 822 headers\n%s\n", headers));
00976 break;
00977 }
00978 }
00979 }
00980
00981 headers = temp+2;
00982 }
00983 *extra_mime_headers = headers;
00984 }
00985 DEBUG_RET();
00986 }
00987
00988
00989 void write_body_part(FILE* f_output, char *body, int32_t body_was_unicode, char *mime, char *charset, char *boundary, pst_file* pst)
00990 {
00991 char *needfree = NULL;
00992 DEBUG_ENT("write_body_part");
00993 if (body_was_unicode && (strcasecmp("utf-8", charset))) {
00994
00995
00996
00997 size_t rc;
00998 DEBUG_EMAIL(("Convert %s utf-8 to %s\n", mime, charset));
00999 vbuf *newer = vballoc(2);
01000 rc = vb_utf8to8bit(newer, body, strlen(body) + 1, charset);
01001 if (rc == (size_t)-1) {
01002
01003 free(newer->b);
01004 DEBUG_EMAIL(("Failed to convert %s utf-8 to %s\n", mime, charset));
01005 charset = "utf-8";
01006 }
01007 else {
01008 needfree = body = newer->b;
01009 }
01010 free(newer);
01011 }
01012 removeCR(body);
01013 int base64 = test_base64(body);
01014 fprintf(f_output, "\n--%s\n", boundary);
01015 fprintf(f_output, "Content-Type: %s; charset=\"%s\"\n", mime, charset);
01016 if (base64) fprintf(f_output, "Content-Transfer-Encoding: base64\n");
01017 fprintf(f_output, "\n");
01018 if (base64) {
01019 char *enc = base64_encode(body, strlen(body));
01020 if (enc) {
01021 write_email_body(f_output, enc);
01022 fprintf(f_output, "\n");
01023 free(enc);
01024 }
01025 }
01026 else {
01027 write_email_body(f_output, body);
01028 }
01029 if (needfree) free(needfree);
01030 DEBUG_RET();
01031 }
01032
01033
01034 const char* codepage(int cp);
01035 const char* codepage(int cp) {
01036 static char buffer[20];
01037 switch (cp) {
01038 case 932 : return "iso-2022-jp";
01039 case 936 : return "gb2313";
01040 case 950 : return "big5";
01041 case 20127 : return "us-ascii";
01042 case 20269 : return "iso-6937";
01043 case 20865 : return "iso-8859-15";
01044 case 20866 : return "koi8-r";
01045 case 21866 : return "koi8-u";
01046 case 28591 : return "iso-8859-1";
01047 case 28592 : return "iso-8859-2";
01048 case 28595 : return "iso-8859-5";
01049 case 28596 : return "iso-8859-6";
01050 case 28597 : return "iso-8859-7";
01051 case 28598 : return "iso-8859-8";
01052 case 28599 : return "iso-8859-9";
01053 case 50220 : return "iso-2022-jp";
01054 case 50221 : return "csiso2022jp";
01055 case 51932 : return "euc-jp";
01056 case 51949 : return "euc-kr";
01057 case 65000 : return "utf-7";
01058 case 65001 : return "utf-8";
01059 default :
01060 snprintf(buffer, sizeof(buffer), "windows-%d", cp);
01061 return buffer;
01062 }
01063 return NULL;
01064 }
01065
01066
01067 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)
01068 {
01069 char boundary[60];
01070 char body_charset[60];
01071 char body_report[60];
01072 char sender[60];
01073 int sender_known = 0;
01074 char *temp = NULL;
01075 int attach_num;
01076 time_t em_time;
01077 char *c_time;
01078 char *headers = (item->email->header) ? item->email->header : *extra_mime_headers;
01079 int has_from, has_subject, has_to, has_cc, has_date, has_msgid;
01080 has_from = has_subject = has_to = has_cc = has_date = has_msgid = 0;
01081 DEBUG_ENT("write_normal_email");
01082
01083
01084 snprintf(body_charset, sizeof(body_charset), "%s",
01085 (item->email->body_charset) ? item->email->body_charset :
01086 (item->email->message_codepage) ? codepage(item->email->message_codepage) :
01087 (item->email->internet_cpid) ? codepage(item->email->internet_cpid) :
01088 "utf-8");
01089 body_report[0] = '\0';
01090
01091
01092 if (item->email->sender_address && strchr(item->email->sender_address, '@')) {
01093 temp = item->email->sender_address;
01094 sender_known = 1;
01095 }
01096 else {
01097 temp = "MAILER-DAEMON";
01098 }
01099 snprintf(sender, sizeof(sender), "%s", temp);
01100
01101
01102 if (item->email->sent_date) {
01103 em_time = fileTimeToUnixTime(item->email->sent_date, 0);
01104 c_time = ctime(&em_time);
01105 if (c_time)
01106 c_time[strlen(c_time)-1] = '\0';
01107 else
01108 c_time = "Fri Dec 28 12:06:21 2001";
01109 } else
01110 c_time= "Fri Dec 28 12:06:21 2001";
01111
01112
01113 snprintf(boundary, sizeof(boundary), "--boundary-LibPST-iamunique-%i_-_-", rand());
01114
01115
01116 if (headers ) {
01117 char *t;
01118 removeCR(headers);
01119
01120 temp = strstr(headers, "\n\n");
01121 if (temp) {
01122
01123 temp[1] = '\0';
01124
01125
01126 *extra_mime_headers = temp+2;
01127 DEBUG_EMAIL(("Found extra mime headers\n%s\n", temp+2));
01128 }
01129
01130
01131 header_has_field(headers, "\nFrom: ", &has_from);
01132 header_has_field(headers, "\nTo: ", &has_to);
01133 header_has_field(headers, "\nSubject: ", &has_subject);
01134 header_has_field(headers, "\nDate: ", &has_date);
01135 header_has_field(headers, "\nCC: ", &has_cc);
01136 header_has_field(headers, "\nMessage-Id: ", &has_msgid);
01137
01138
01139 t = header_get_field(headers, "\nContent-Type: ");
01140 header_get_subfield(t, "charset", body_charset, sizeof(body_charset));
01141 header_get_subfield(t, "report-type", body_report, sizeof(body_report));
01142
01143
01144 if (!sender_known) {
01145 t = header_get_field(headers, "\nFrom: ");
01146 if (t) {
01147
01148 t++;
01149 char *n = strchr(t, '\n');
01150 char *s = strchr(t, '<');
01151 char *e = strchr(t, '>');
01152 if (s && e && n && (s < e) && (e < n)) {
01153 char save = *e;
01154 *e = '\0';
01155 snprintf(sender, sizeof(sender), "%s", s+1);
01156 *e = save;
01157 }
01158 }
01159 }
01160
01161
01162 header_strip_field(headers, "\nMicrosoft Mail Internet Headers");
01163 header_strip_field(headers, "\nMIME-Version: ");
01164 header_strip_field(headers, "\nContent-Type: ");
01165 header_strip_field(headers, "\nContent-Transfer-Encoding: ");
01166 header_strip_field(headers, "\nContent-class: ");
01167 header_strip_field(headers, "\nX-MimeOLE: ");
01168 header_strip_field(headers, "\nBcc:");
01169 header_strip_field(headers, "\nX-From_: ");
01170 }
01171
01172 DEBUG_EMAIL(("About to print Header\n"));
01173
01174 if (item && item->email && item->email->subject && item->email->subject->subj) {
01175 DEBUG_EMAIL(("item->email->subject->subj = %s\n", item->email->subject->subj));
01176 }
01177
01178 if (mode != MODE_SEPARATE) {
01179
01180
01181
01182
01183 fprintf(f_output, "From \"%s\" %s\n", sender, c_time);
01184 }
01185
01186
01187 if (headers) {
01188 int len;
01189 fprintf(f_output, "%s", headers);
01190
01191 len = strlen(headers);
01192 if (!len || (headers[len-1] != '\n')) fprintf(f_output, "\n");
01193 }
01194
01195
01196
01197 if (!has_from) {
01198 fprintf(f_output, "From: \"%s\" <%s>\n", item->email->outlook_sender_name, sender);
01199 }
01200
01201 if (!has_subject) {
01202 if (item->email->subject && item->email->subject->subj) {
01203 fprintf(f_output, "Subject: %s\n", item->email->subject->subj);
01204 } else {
01205 fprintf(f_output, "Subject: \n");
01206 }
01207 }
01208
01209 if (!has_to && item->email->sentto_address) {
01210 fprintf(f_output, "To: %s\n", item->email->sentto_address);
01211 }
01212
01213 if (!has_cc && item->email->cc_address) {
01214 fprintf(f_output, "Cc: %s\n", item->email->cc_address);
01215 }
01216
01217 if (!has_date && item->email->sent_date) {
01218 char c_time[C_TIME_SIZE];
01219 strftime(c_time, C_TIME_SIZE, "%a, %d %b %Y %H:%M:%S %z", gmtime(&em_time));
01220 fprintf(f_output, "Date: %s\n", c_time);
01221 }
01222
01223 if (!has_msgid && item->email->messageid) {
01224 fprintf(f_output, "Message-Id: %s\n", item->email->messageid);
01225 }
01226
01227
01228
01229 if (item->email->sender_address && !strchr(item->email->sender_address, '@')
01230 && strcmp(item->email->sender_address, ".")) {
01231 fprintf(f_output, "X-libpst-forensic-sender: %s\n", item->email->sender_address);
01232 }
01233
01234 if (item->email->bcc_address) {
01235 fprintf(f_output, "X-libpst-forensic-bcc: %s\n", item->email->bcc_address);
01236 }
01237
01238
01239 fprintf(f_output, "MIME-Version: 1.0\n");
01240 if (body_report[0] != '\0') {
01241
01242 fprintf(f_output, "Content-Type: multipart/report; report-type=%s;\n\tboundary=\"%s\"\n", body_report, boundary);
01243 }
01244 else if (item->attach || (item->email->rtf_compressed && save_rtf)
01245 || item->email->encrypted_body
01246 || item->email->encrypted_htmlbody) {
01247
01248 fprintf(f_output, "Content-Type: multipart/mixed;\n\tboundary=\"%s\"\n", boundary);
01249 } else {
01250
01251 fprintf(f_output, "Content-Type: multipart/alternative;\n\tboundary=\"%s\"\n", boundary);
01252 }
01253 fprintf(f_output, "\n");
01254
01255
01256 if (item->email->body) {
01257 write_body_part(f_output, item->email->body, item->email->body_was_unicode, "text/plain", body_charset, boundary, pst);
01258 }
01259
01260 if ((item->email->report_text) && (body_report[0] != '\0')) {
01261 write_body_part(f_output, item->email->report_text, item->email->report_was_unicode, "text/plain", body_charset, boundary, pst);
01262 fprintf(f_output, "\n");
01263 }
01264
01265 if (item->email->htmlbody) {
01266 find_html_charset(item->email->htmlbody, body_charset, sizeof(body_charset));
01267 write_body_part(f_output, item->email->htmlbody, item->email->htmlbody_was_unicode, "text/html", body_charset, boundary, pst);
01268 }
01269
01270 if (item->email->rtf_compressed && save_rtf) {
01271 pst_item_attach* attach = (pst_item_attach*)xmalloc(sizeof(pst_item_attach));
01272 DEBUG_EMAIL(("Adding RTF body as attachment\n"));
01273 memset(attach, 0, sizeof(pst_item_attach));
01274 attach->next = item->attach;
01275 item->attach = attach;
01276 attach->data = lzfu_decompress(item->email->rtf_compressed, item->email->rtf_compressed_size, &attach->size);
01277 attach->filename2 = strdup(RTF_ATTACH_NAME);
01278 attach->mimetype = strdup(RTF_ATTACH_TYPE);
01279 }
01280
01281 if (item->email->encrypted_body || item->email->encrypted_htmlbody) {
01282
01283 if (item->email->encrypted_body) {
01284 pst_item_attach* attach = (pst_item_attach*)xmalloc(sizeof(pst_item_attach));
01285 DEBUG_EMAIL(("Adding Encrypted Body as attachment\n"));
01286 attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach));
01287 memset(attach, 0, sizeof(pst_item_attach));
01288 attach->next = item->attach;
01289 item->attach = attach;
01290 attach->data = item->email->encrypted_body;
01291 attach->size = item->email->encrypted_body_size;
01292 item->email->encrypted_body = NULL;
01293 }
01294
01295 if (item->email->encrypted_htmlbody) {
01296 pst_item_attach* attach = (pst_item_attach*)xmalloc(sizeof(pst_item_attach));
01297 DEBUG_EMAIL(("Adding encrypted HTML body as attachment\n"));
01298 attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach));
01299 memset(attach, 0, sizeof(pst_item_attach));
01300 attach->next = item->attach;
01301 item->attach = attach;
01302 attach->data = item->email->encrypted_htmlbody;
01303 attach->size = item->email->encrypted_htmlbody_size;
01304 item->email->encrypted_htmlbody = NULL;
01305 }
01306 write_email_body(f_output, "The body of this email is encrypted. This isn't supported yet, but the body is now an attachment\n");
01307 }
01308
01309
01310 {
01311 pst_item_attach* attach;
01312 attach_num = 0;
01313 for (attach = item->attach; attach; attach = attach->next) {
01314 DEBUG_EMAIL(("Attempting Attachment encoding\n"));
01315 if (!attach->data && attach->mimetype && !strcmp(attach->mimetype, RFC822)) {
01316 DEBUG_EMAIL(("seem to have special embedded message attachment\n"));
01317 find_rfc822_headers(extra_mime_headers);
01318 write_embedded_message(f_output, attach, boundary, pst, extra_mime_headers);
01319 }
01320 else if (mode == MODE_SEPARATE && !mode_MH)
01321 write_separate_attachment(f_name, attach, ++attach_num, pst);
01322 else
01323 write_inline_attachment(f_output, attach, boundary, pst);
01324 }
01325 }
01326
01327
01328 if (mode != MODE_SEPARATE) {
01329 DEBUG_EMAIL(("Writing buffer between emails\n"));
01330 fprintf(f_output, "\n--%s--\n", boundary);
01331 fprintf(f_output, "\n\n");
01332 }
01333 DEBUG_RET();
01334 }
01335
01336
01337 void write_vcard(FILE* f_output, pst_item_contact* contact, char comment[])
01338 {
01339
01340
01341
01342
01343 DEBUG_ENT("write_vcard");
01344
01345 fprintf(f_output, "BEGIN:VCARD\n");
01346 fprintf(f_output, "FN:%s\n", pst_rfc2426_escape(contact->fullname));
01347
01348
01349 fprintf(f_output, "N:%s;", (!contact->surname) ? "" : pst_rfc2426_escape(contact->surname));
01350 fprintf(f_output, "%s;", (!contact->first_name) ? "" : pst_rfc2426_escape(contact->first_name));
01351 fprintf(f_output, "%s;", (!contact->middle_name) ? "" : pst_rfc2426_escape(contact->middle_name));
01352 fprintf(f_output, "%s;", (!contact->display_name_prefix) ? "" : pst_rfc2426_escape(contact->display_name_prefix));
01353 fprintf(f_output, "%s\n", (!contact->suffix) ? "" : pst_rfc2426_escape(contact->suffix));
01354
01355 if (contact->nickname)
01356 fprintf(f_output, "NICKNAME:%s\n", pst_rfc2426_escape(contact->nickname));
01357 if (contact->address1)
01358 fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address1));
01359 if (contact->address2)
01360 fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address2));
01361 if (contact->address3)
01362 fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address3));
01363 if (contact->birthday)
01364 fprintf(f_output, "BDAY:%s\n", pst_rfc2425_datetime_format(contact->birthday));
01365
01366 if (contact->home_address) {
01367
01368 fprintf(f_output, "ADR;TYPE=home:%s;", (!contact->home_po_box) ? "" : pst_rfc2426_escape(contact->home_po_box));
01369 fprintf(f_output, "%s;", "");
01370 fprintf(f_output, "%s;", (!contact->home_street) ? "" : pst_rfc2426_escape(contact->home_street));
01371 fprintf(f_output, "%s;", (!contact->home_city) ? "" : pst_rfc2426_escape(contact->home_city));
01372 fprintf(f_output, "%s;", (!contact->home_state) ? "" : pst_rfc2426_escape(contact->home_state));
01373 fprintf(f_output, "%s;", (!contact->home_postal_code) ? "" : pst_rfc2426_escape(contact->home_postal_code));
01374 fprintf(f_output, "%s\n", (!contact->home_country) ? "" : pst_rfc2426_escape(contact->home_country));
01375 fprintf(f_output, "LABEL;TYPE=home:%s\n", pst_rfc2426_escape(contact->home_address));
01376 }
01377
01378 if (contact->business_address) {
01379
01380 fprintf(f_output, "ADR;TYPE=work:%s;", (!contact->business_po_box) ? "" : pst_rfc2426_escape(contact->business_po_box));
01381 fprintf(f_output, "%s;", "");
01382 fprintf(f_output, "%s;", (!contact->business_street) ? "" : pst_rfc2426_escape(contact->business_street));
01383 fprintf(f_output, "%s;", (!contact->business_city) ? "" : pst_rfc2426_escape(contact->business_city));
01384 fprintf(f_output, "%s;", (!contact->business_state) ? "" : pst_rfc2426_escape(contact->business_state));
01385 fprintf(f_output, "%s;", (!contact->business_postal_code) ? "" : pst_rfc2426_escape(contact->business_postal_code));
01386 fprintf(f_output, "%s\n", (!contact->business_country) ? "" : pst_rfc2426_escape(contact->business_country));
01387 fprintf(f_output, "LABEL;TYPE=work:%s\n", pst_rfc2426_escape(contact->business_address));
01388 }
01389
01390 if (contact->other_address) {
01391
01392 fprintf(f_output, "ADR;TYPE=postal:%s;",(!contact->other_po_box) ? "" : pst_rfc2426_escape(contact->other_po_box));
01393 fprintf(f_output, "%s;", "");
01394 fprintf(f_output, "%s;", (!contact->other_street) ? "" : pst_rfc2426_escape(contact->other_street));
01395 fprintf(f_output, "%s;", (!contact->other_city) ? "" : pst_rfc2426_escape(contact->other_city));
01396 fprintf(f_output, "%s;", (!contact->other_state) ? "" : pst_rfc2426_escape(contact->other_state));
01397 fprintf(f_output, "%s;", (!contact->other_postal_code) ? "" : pst_rfc2426_escape(contact->other_postal_code));
01398 fprintf(f_output, "%s\n", (!contact->other_country) ? "" : pst_rfc2426_escape(contact->other_country));
01399 fprintf(f_output, "LABEL;TYPE=postal:%s\n", pst_rfc2426_escape(contact->other_address));
01400 }
01401
01402 if (contact->business_fax) fprintf(f_output, "TEL;TYPE=work,fax:%s\n", pst_rfc2426_escape(contact->business_fax));
01403 if (contact->business_phone) fprintf(f_output, "TEL;TYPE=work,voice:%s\n", pst_rfc2426_escape(contact->business_phone));
01404 if (contact->business_phone2) fprintf(f_output, "TEL;TYPE=work,voice:%s\n", pst_rfc2426_escape(contact->business_phone2));
01405 if (contact->car_phone) fprintf(f_output, "TEL;TYPE=car,voice:%s\n", pst_rfc2426_escape(contact->car_phone));
01406 if (contact->home_fax) fprintf(f_output, "TEL;TYPE=home,fax:%s\n", pst_rfc2426_escape(contact->home_fax));
01407 if (contact->home_phone) fprintf(f_output, "TEL;TYPE=home,voice:%s\n", pst_rfc2426_escape(contact->home_phone));
01408 if (contact->home_phone2) fprintf(f_output, "TEL;TYPE=home,voice:%s\n", pst_rfc2426_escape(contact->home_phone2));
01409 if (contact->isdn_phone) fprintf(f_output, "TEL;TYPE=isdn:%s\n", pst_rfc2426_escape(contact->isdn_phone));
01410 if (contact->mobile_phone) fprintf(f_output, "TEL;TYPE=cell,voice:%s\n", pst_rfc2426_escape(contact->mobile_phone));
01411 if (contact->other_phone) fprintf(f_output, "TEL;TYPE=msg:%s\n", pst_rfc2426_escape(contact->other_phone));
01412 if (contact->pager_phone) fprintf(f_output, "TEL;TYPE=pager:%s\n", pst_rfc2426_escape(contact->pager_phone));
01413 if (contact->primary_fax) fprintf(f_output, "TEL;TYPE=fax,pref:%s\n", pst_rfc2426_escape(contact->primary_fax));
01414 if (contact->primary_phone) fprintf(f_output, "TEL;TYPE=phone,pref:%s\n", pst_rfc2426_escape(contact->primary_phone));
01415 if (contact->radio_phone) fprintf(f_output, "TEL;TYPE=pcs:%s\n", pst_rfc2426_escape(contact->radio_phone));
01416 if (contact->telex) fprintf(f_output, "TEL;TYPE=bbs:%s\n", pst_rfc2426_escape(contact->telex));
01417 if (contact->job_title) fprintf(f_output, "TITLE:%s\n", pst_rfc2426_escape(contact->job_title));
01418 if (contact->profession) fprintf(f_output, "ROLE:%s\n", pst_rfc2426_escape(contact->profession));
01419 if (contact->assistant_name || contact->assistant_phone) {
01420 fprintf(f_output, "AGENT:BEGIN:VCARD\n");
01421 if (contact->assistant_name) fprintf(f_output, "FN:%s\n", pst_rfc2426_escape(contact->assistant_name));
01422 if (contact->assistant_phone) fprintf(f_output, "TEL:%s\n", pst_rfc2426_escape(contact->assistant_phone));
01423 }
01424 if (contact->company_name) fprintf(f_output, "ORG:%s\n", pst_rfc2426_escape(contact->company_name));
01425 if (comment) fprintf(f_output, "NOTE:%s\n", pst_rfc2426_escape(comment));
01426
01427 fprintf(f_output, "VERSION: 3.0\n");
01428 fprintf(f_output, "END:VCARD\n\n");
01429 DEBUG_RET();
01430 }
01431
01432
01433 void write_appointment(FILE* f_output, pst_item_appointment* appointment,
01434 pst_item_email* email, FILETIME* create_date, FILETIME* modify_date)
01435 {
01436 fprintf(f_output, "BEGIN:VEVENT\n");
01437 if (create_date)
01438 fprintf(f_output, "CREATED:%s\n",
01439 pst_rfc2445_datetime_format(create_date));
01440 if (modify_date)
01441 fprintf(f_output, "LAST-MOD:%s\n",
01442 pst_rfc2445_datetime_format(modify_date));
01443 if (email && email->subject)
01444 fprintf(f_output, "SUMMARY:%s\n",
01445 pst_rfc2426_escape(email->subject->subj));
01446 if (email && email->body)
01447 fprintf(f_output, "DESCRIPTION:%s\n",
01448 pst_rfc2426_escape(email->body));
01449 if (appointment && appointment->start)
01450 fprintf(f_output, "DTSTART;VALUE=DATE-TIME:%s\n",
01451 pst_rfc2445_datetime_format(appointment->start));
01452 if (appointment && appointment->end)
01453 fprintf(f_output, "DTEND;VALUE=DATE-TIME:%s\n",
01454 pst_rfc2445_datetime_format(appointment->end));
01455 if (appointment && appointment->location)
01456 fprintf(f_output, "LOCATION:%s\n",
01457 pst_rfc2426_escape(appointment->location));
01458 if (appointment) {
01459 switch (appointment->showas) {
01460 case PST_FREEBUSY_TENTATIVE:
01461 fprintf(f_output, "STATUS:TENTATIVE\n");
01462 break;
01463 case PST_FREEBUSY_FREE:
01464
01465 fprintf(f_output, "TRANSP:TRANSPARENT\n");
01466 case PST_FREEBUSY_BUSY:
01467 case PST_FREEBUSY_OUT_OF_OFFICE:
01468 fprintf(f_output, "STATUS:CONFIRMED\n");
01469 break;
01470 }
01471 switch (appointment->label) {
01472 case PST_APP_LABEL_NONE:
01473 fprintf(f_output, "CATEGORIES:NONE\n");
01474 break;
01475 case PST_APP_LABEL_IMPORTANT:
01476 fprintf(f_output, "CATEGORIES:IMPORTANT\n");
01477 break;
01478 case PST_APP_LABEL_BUSINESS:
01479 fprintf(f_output, "CATEGORIES:BUSINESS\n");
01480 break;
01481 case PST_APP_LABEL_PERSONAL:
01482 fprintf(f_output, "CATEGORIES:PERSONAL\n");
01483 break;
01484 case PST_APP_LABEL_VACATION:
01485 fprintf(f_output, "CATEGORIES:VACATION\n");
01486 break;
01487 case PST_APP_LABEL_MUST_ATTEND:
01488 fprintf(f_output, "CATEGORIES:MUST-ATTEND\n");
01489 break;
01490 case PST_APP_LABEL_TRAVEL_REQ:
01491 fprintf(f_output, "CATEGORIES:TRAVEL-REQUIRED\n");
01492 break;
01493 case PST_APP_LABEL_NEEDS_PREP:
01494 fprintf(f_output, "CATEGORIES:NEEDS-PREPARATION\n");
01495 break;
01496 case PST_APP_LABEL_BIRTHDAY:
01497 fprintf(f_output, "CATEGORIES:BIRTHDAY\n");
01498 break;
01499 case PST_APP_LABEL_ANNIVERSARY:
01500 fprintf(f_output, "CATEGORIES:ANNIVERSARY\n");
01501 break;
01502 case PST_APP_LABEL_PHONE_CALL:
01503 fprintf(f_output, "CATEGORIES:PHONE-CALL\n");
01504 break;
01505 }
01506 }
01507 fprintf(f_output, "END:VEVENT\n\n");
01508 }
01509
01510
01511 void create_enter_dir(struct file_ll* f, pst_item *item)
01512 {
01513 f->email_count = 0;
01514 f->skip_count = 0;
01515 f->type = item->type;
01516 f->stored_count = (item->folder) ? item->folder->email_count : 0;
01517
01518 DEBUG_ENT("create_enter_dir");
01519 if (mode == MODE_KMAIL)
01520 f->name = mk_kmail_dir(item->file_as);
01521 else if (mode == MODE_RECURSE)
01522 f->name = mk_recurse_dir(item->file_as);
01523 else if (mode == MODE_SEPARATE) {
01524
01525 mk_separate_dir(item->file_as);
01526 f->name = (char*) xmalloc(10);
01527 memset(f->name, 0, 10);
01528
01529 } else {
01530 f->name = (char*) xmalloc(strlen(item->file_as)+strlen(OUTPUT_TEMPLATE)+1);
01531 sprintf(f->name, OUTPUT_TEMPLATE, item->file_as);
01532 }
01533
01534 f->dname = (char*) xmalloc(strlen(item->file_as)+1);
01535 strcpy(f->dname, item->file_as);
01536
01537 if (overwrite != 1) {
01538 int x = 0;
01539 char *temp = (char*) xmalloc (strlen(f->name)+10);
01540
01541 sprintf(temp, "%s", f->name);
01542 check_filename(temp);
01543 while ((f->output = fopen(temp, "r"))) {
01544 DEBUG_MAIN(("need to increase filename because one already exists with that name\n"));
01545 DEBUG_MAIN(("- increasing it to %s%d\n", f->name, x));
01546 x++;
01547 sprintf(temp, "%s%08d", f->name, x);
01548 DEBUG_MAIN(("- trying \"%s\"\n", f->name));
01549 if (x == 99999999) {
01550 DIE(("create_enter_dir: Why can I not create a folder %s? I have tried %i extensions...\n", f->name, x));
01551 }
01552 fclose(f->output);
01553 }
01554 if (x > 0) {
01555 free (f->name);
01556 f->name = temp;
01557 } else {
01558 free(temp);
01559 }
01560 }
01561
01562 DEBUG_MAIN(("f->name = %s\nitem->folder_name = %s\n", f->name, item->file_as));
01563 if (mode != MODE_SEPARATE) {
01564 check_filename(f->name);
01565 if (!(f->output = fopen(f->name, "w"))) {
01566 DIE(("create_enter_dir: Could not open file \"%s\" for write\n", f->name));
01567 }
01568 }
01569 DEBUG_RET();
01570 }
01571
01572
01573 void close_enter_dir(struct file_ll *f)
01574 {
01575 DEBUG_MAIN(("main: Email Count for folder %s is %i\n", f->dname, f->email_count));
01576 if (output_mode != OUTPUT_QUIET)
01577 printf("\t\"%s\" - %i items done, skipped %i, should have been %i\n",
01578 f->dname, f->email_count, f->skip_count, f->stored_count);
01579 if (f->output) fclose(f->output);
01580 free(f->name);
01581 free(f->dname);
01582
01583 if (mode == MODE_KMAIL)
01584 close_kmail_dir();
01585 else if (mode == MODE_RECURSE)
01586 close_recurse_dir();
01587 else if (mode == MODE_SEPARATE)
01588 close_separate_dir();
01589 }
01590