Main Page | Namespace List | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

readpst.c

Go to the documentation of this file.
00001 /***
00002  * readpst.c
00003  * Part of the LibPST project
00004  * Written by David Smith
00005  *            dave.s@earthcorp.com
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 // max size of the c_time char*. It will store the date of the email
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 // Normal mode just creates mbox format files in the current directory. Each file is named
00067 // the same as the folder's name that it represents
00068 #define MODE_NORMAL 0
00069 
00070 // KMail mode creates a directory structure suitable for being used directly
00071 // by the KMail application
00072 #define MODE_KMAIL 1
00073 
00074 // recurse mode creates a directory structure like the PST file. Each directory
00075 // contains only one file which stores the emails in mbox format.
00076 #define MODE_RECURSE 2
00077 
00078 // separate mode creates the same directory structure as recurse. The emails are stored in
00079 // separate files, numbering from 1 upward. Attachments belonging to the emails are
00080 // saved as email_no-filename (e.g. 1-samplefile.doc or 000001-Attachment2.zip)
00081 #define MODE_SEPARATE 3
00082 
00083 // Decrypt the whole file (even the parts that aren't encrypted) and ralph it to stdout
00084 #define MODE_DECSPEW 4
00085 
00086 
00087 // Output Normal just prints the standard information about what is going on
00088 #define OUTPUT_NORMAL 0
00089 
00090 // Output Quiet is provided so that only errors are printed
00091 #define OUTPUT_QUIET 1
00092 
00093 // default mime-type for attachments that have a null mime-type
00094 #define MIME_TYPE_DEFAULT "application/octet-stream"
00095 #define RFC822            "message/rfc822"
00096 
00097 // output mode for contacts
00098 #define CMODE_VCARD 0
00099 #define CMODE_LIST  1
00100 
00101 // output mode for deleted items
00102 #define DMODE_EXCLUDE 0
00103 #define DMODE_INCLUDE 1
00104 
00105 // output settings for RTF bodies
00106 // filename for the attachment
00107 #define RTF_ATTACH_NAME "rtf-body.rtf"
00108 // mime type for the attachment
00109 #define RTF_ATTACH_TYPE "application/rtf"
00110 
00111 // global settings
00112 int mode         = MODE_NORMAL;
00113 int mode_MH      = 0;   // a submode of MODE_SEPARATE
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                 //if this is a non-empty folder other than deleted items, we want to recurse into it
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             // there should only be one message_store, and we have already done it
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;               //temporary char pointer
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     // command-line option handling
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         // force a log file
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; // first record is main record
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     // default the file_as to the same as the main filename if it doesn't exist
00401     if (!item->file_as.str) {
00402         if (!(temp = strrchr(fname, '/')))
00403             if (!(temp = strrchr(fname, '\\')))
00404                 temp = fname;
00405             else
00406                 temp++; // get past the "\\"
00407         else
00408             temp++; // get past the "/"
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);    // do the children of TOPF
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); //write just a line
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     // converts \r\n to \n
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     //change to that directory
00506     //make a directory based on OUTPUT_KMAIL_DIR_TEMPLATE
00507     //allocate space for OUTPUT_TEMPLATE and form a char* with fname
00508     //return that value
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         //error occured
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     //we should remove any existing indexes created by KMail, cause they might be different now
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     // change ..
00545     int x;
00546     DEBUG_ENT("close_kmail_dir");
00547     if (kmail_chdir) { //only free kmail_chdir if not NULL. do not change directory
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 // this will create a directory by that name, then make an mbox file inside
00562 // that dir.  any subsequent dirs will be created by name, and they will
00563 // contain mbox files
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) { // not an error because it exists
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); // enough for 9 digits allocated above
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) { // if there is an error, and it doesn't already exist
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         // we should probably delete all files from this directory
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     // we don't return a filename here cause it isn't necessary.
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) { // bigger than nine 9's
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     // my_stristr varies from strstr in that its searches are case-insensitive
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             // move y on one
00713             y++;
00714             if (!z) {
00715                 z = x; // store first position in haystack where a match is made
00716             }
00717         } else {
00718             y = needle; // reset y to the beginning of the needle
00719             z = NULL; // reset the haystack storage point
00720         }
00721         x++; // advance the search in the haystack
00722     }
00723     // If the haystack ended before our search finished, it's not a match.
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         // while there are characters in the second string that we don't want
00738         *t = '_'; //replace them with an underscore
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     // If there is a long filename (filename2) use that, otherwise
00751     // use the 8.3 filename (filename1)
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         // make sure we can fetch data from the id
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         // generate our own (dummy) filename for the attachement
00769         temp = xmalloc(strlen(f_name)+15);
00770         sprintf(temp, "%s-attach%i", f_name, attach_num);
00771     } else {
00772         // have an attachment name, make sure it's unique
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; // base64 encoded attachment
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         // make sure we can fetch data from the id
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     // If there is a long filename (filename2) use that, otherwise
00862     // use the 8.3 filename (filename1)
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);  // caught by valgrind
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);    // skip over subfield=
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;   // use the trailing lf as terminator if nothing better
00915         save = *e;
00916         *e = '\0';
00917             snprintf(body_subfield, size_subfield, "%s", s);  // copy the subfield to our buffer
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 // return pointer to \n at the end of this header field,
00933 // or NULL if this field goes to the end of the string.
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++;   // if *t is not \n, we don't want to keep the \n at *e either.
00951             while (*e != '\0') {
00952                 *t = *e;
00953                 t++;
00954                 e++;
00955             }
00956             *t = '\0';
00957         }
00958         else {
00959             // this was the last header field, truncate the headers
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);    // copy the html charset
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;   // found rfc822 header
01034                         DEBUG_EMAIL(("found 822 headers\n%s\n", headers));
01035                         break;
01036                     }
01037                 }
01038             }
01039             //DEBUG_EMAIL(("skipping to next block after\n%s\n", headers));
01040             headers = temp+2;   // skip to next chunk of headers
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         // try to convert to the specified charset since the target
01053         // is not utf-8, and the data came from a unicode (utf16) field
01054         // and is now in utf-8.
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             // unable to convert, change the charset to utf8
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             // null terminate the output string
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     // setup default body character set and report type
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     // setup default sender
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     // convert the sent date if it exists, or set it to a fixed date
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'; //remove end \n
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     // create our MIME boundary here.
01143     snprintf(boundary, sizeof(boundary), "--boundary-LibPST-iamunique-%i_-_-", rand());
01144 
01145     // we will always look at the headers to discover some stuff
01146     if (headers ) {
01147         char *t;
01148         removeCR(headers);
01149 
01150         temp = strstr(headers, "\n\n");
01151         if (temp) {
01152             // cut off our real rfc822 headers here
01153             temp[1] = '\0';
01154             // pointer to all the embedded MIME headers.
01155             // we use these to find the actual rfc822 headers for embedded message/rfc822 mime parts
01156             *extra_mime_headers = temp+2;
01157             DEBUG_EMAIL(("Found extra mime headers\n%s\n", temp+2));
01158         }
01159 
01160         // Check if the headers have all the necessary fields
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         // look for charset and report-type in Content-Type header
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         // derive a proper sender email address
01174         if (!sender_known) {
01175             t = header_get_field(headers, "\nFrom: ");
01176             if (t) {
01177                 // assume address is on the first line, rather than on a continuation line
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         // Strip out the mime headers and some others that we don't want to emit
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         // most modes need this separator line.
01211         // procmail produces this separator without the quotes around the
01212         // sender email address, but apparently some Mac email client needs
01213         // those quotes, and they don't seem to cause problems for anyone else.
01214         fprintf(f_output, "From \"%s\" %s\n", sender, c_time);
01215     }
01216 
01217     // print the supplied email headers
01218     if (headers) {
01219         int len;
01220         fprintf(f_output, "%s", headers);
01221         // make sure the headers end with a \n
01222         len = strlen(headers);
01223         if (!len || (headers[len-1] != '\n')) fprintf(f_output, "\n");
01224     }
01225 
01226     // create required header fields that are not already written
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     // add forensic headers to capture some .pst stuff that is not really
01262     // needed or used by mail clients
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     // add our own mime headers
01275     fprintf(f_output, "MIME-Version: 1.0\n");
01276     if (body_report[0] != '\0') {
01277         // multipart/report for DSN/MDN reports
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         // use multipart/mixed if we have attachments
01284         fprintf(f_output, "Content-Type: multipart/mixed;\n\tboundary=\"%s\"\n", boundary);
01285     } else {
01286         // else use multipart/alternative
01287         fprintf(f_output, "Content-Type: multipart/alternative;\n\tboundary=\"%s\"\n", boundary);
01288     }
01289     fprintf(f_output, "\n");    // end of headers, start of body
01290 
01291     // now dump the body parts
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         // if either the body or htmlbody is encrypted, add them as attachments
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     // other attachments
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     // end of this mail message
01371     if (mode != MODE_SEPARATE) { /* do not add a boundary after the last attachment for mode_MH */
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     // We can only call rfc escape once per printf, since the second call
01383     // may free the buffer returned by the first call.
01384     // I had tried to place those into a single printf - Carl.
01385 
01386     DEBUG_ENT("write_vcard");
01387 
01388     // make everything utf8
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     // the specification I am following is (hopefully) RFC2426 vCard Mime Directory Profile
01442     fprintf(f_output, "BEGIN:VCARD\n");
01443     fprintf(f_output, "FN:%s\n", pst_rfc2426_escape(contact->fullname.str));
01444 
01445     //fprintf(f_output, "N:%s;%s;%s;%s;%s\n",
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         //fprintf(f_output, "ADR;TYPE=home:%s;%s;%s;%s;%s;%s;%s\n",
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;",                ""); // extended Address
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         //fprintf(f_output, "ADR;TYPE=work:%s;%s;%s;%s;%s;%s;%s\n",
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;",                ""); // extended Address
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         //fprintf(f_output, "ADR;TYPE=postal:%s;%s;%s;%s;%s;%s;%s\n",
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;",                ""); // extended Address
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     // make everything utf8
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                 // mark as transparent and as confirmed
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         // do similar stuff to recurse here.
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); //enough room for 10 digits
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) { //then the f->name should change
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 

Generated on Thu Mar 19 16:39:26 2009 for 'LibPst' by  doxygen 1.3.9.1