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