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 #include "define.h"
00008 #include "libstrfunc.h"
00009 #include "libpst.h"
00010 #include "common.h"
00011 #include "timeconv.h"
00012 #include "lzfu.h"
00013 
00014 #define OUTPUT_TEMPLATE "%s"
00015 #define OUTPUT_KMAIL_DIR_TEMPLATE ".%s.directory"
00016 #define KMAIL_INDEX ".%s.index"
00017 #define SEP_MAIL_FILE_TEMPLATE "%i" /* "%09i" */
00018 
00019 // max size of the c_time char*. It will store the date of the email
00020 #define C_TIME_SIZE 500
00021 
00022 struct file_ll {
00023     char *name;
00024     char *dname;
00025     FILE * output;
00026     int32_t stored_count;
00027     int32_t email_count;
00028     int32_t skip_count;
00029     int32_t type;
00030 };
00031 
00032 void      process(pst_item *outeritem, pst_desc_ll *d_ptr);
00033 void      write_email_body(FILE *f, char *body);
00034 char*     removeCR (char *c);
00035 int       usage();
00036 int       version();
00037 char*     mk_kmail_dir(char*);
00038 int       close_kmail_dir();
00039 char*     mk_recurse_dir(char*);
00040 int       close_recurse_dir();
00041 char*     mk_separate_dir(char *dir);
00042 int       close_separate_dir();
00043 int       mk_separate_file(struct file_ll *f);
00044 char*     my_stristr(char *haystack, char *needle);
00045 void      check_filename(char *fname);
00046 char*     skip_header_prologue(char *headers);
00047 void      write_separate_attachment(char f_name[], pst_item_attach* current_attach, int attach_num, pst_file* pst);
00048 void      write_inline_attachment(FILE* f_output, pst_item_attach* current_attach, char boundary[], pst_file* pst);
00049 void      write_normal_email(FILE* f_output, char f_name[], pst_item* item, int mode, int mode_MH, pst_file* pst, int save_rtf);
00050 void      write_vcard(FILE* f_output, pst_item_contact* contact, char comment[]);
00051 void      write_appointment(FILE* f_output, pst_item_appointment* appointment,
00052                             pst_item_email* email, FILETIME* create_date, FILETIME* modify_date);
00053 void      create_enter_dir(struct file_ll* f, pst_item *item);
00054 void      close_enter_dir(struct file_ll *f);
00055 
00056 char*  prog_name;
00057 char*  output_dir = ".";
00058 char*  kmail_chdir = NULL;
00059 
00060 // Normal mode just creates mbox format files in the current directory. Each file is named
00061 // the same as the folder's name that it represents
00062 #define MODE_NORMAL 0
00063 
00064 // KMail mode creates a directory structure suitable for being used directly
00065 // by the KMail application
00066 #define MODE_KMAIL 1
00067 
00068 // recurse mode creates a directory structure like the PST file. Each directory
00069 // contains only one file which stores the emails in mbox format.
00070 #define MODE_RECURSE 2
00071 
00072 // separate mode creates the same directory structure as recurse. The emails are stored in
00073 // separate files, numbering from 1 upward. Attachments belonging to the emails are
00074 // saved as email_no-filename (e.g. 1-samplefile.doc or 000001-Attachment2.zip)
00075 #define MODE_SEPARATE 3
00076 
00077 // Decrypt the whole file (even the parts that aren't encrypted) and ralph it to stdout
00078 #define MODE_DECSPEW 4
00079 
00080 
00081 // Output Normal just prints the standard information about what is going on
00082 #define OUTPUT_NORMAL 0
00083 
00084 // Output Quiet is provided so that only errors are printed
00085 #define OUTPUT_QUIET 1
00086 
00087 // default mime-type for attachments that have a null mime-type
00088 #define MIME_TYPE_DEFAULT "application/octet-stream"
00089 
00090 // output mode for contacts
00091 #define CMODE_VCARD 0
00092 #define CMODE_LIST  1
00093 
00094 // output mode for deleted items
00095 #define DMODE_EXCLUDE 0
00096 #define DMODE_INCLUDE 1
00097 
00098 // output settings for RTF bodies
00099 // filename for the attachment
00100 #define RTF_ATTACH_NAME "rtf-body.rtf"
00101 // mime type for the attachment
00102 #define RTF_ATTACH_TYPE "application/rtf"
00103 
00104 // global settings
00105 int mode = MODE_NORMAL;
00106 int mode_MH = 0;
00107 int output_mode = OUTPUT_NORMAL;
00108 int contact_mode = CMODE_VCARD;
00109 int deleted_mode = DMODE_EXCLUDE;
00110 int overwrite = 0;
00111 int save_rtf_body = 1;
00112 pst_file pstfile;
00113 
00114 
00115 
00116 void process(pst_item *outeritem, pst_desc_ll *d_ptr)
00117 {
00118     struct file_ll ff;
00119     pst_item *item = NULL;
00120 
00121     DEBUG_ENT("process");
00122     memset(&ff, 0, sizeof(ff));
00123     create_enter_dir(&ff, outeritem);
00124 
00125     while (d_ptr) {
00126         DEBUG_MAIN(("main: New item record\n"));
00127         if (!d_ptr->desc) {
00128             DEBUG_WARN(("main: ERROR ?? item's desc record is NULL\n"));
00129             ff.skip_count++;
00130         }
00131         else {
00132             DEBUG_MAIN(("main: Desc Email ID %#x [d_ptr->id = %#x]\n", d_ptr->desc->id, d_ptr->id));
00133 
00134             item = pst_parse_item(&pstfile, d_ptr);
00135             DEBUG_MAIN(("main: About to process item\n"));
00136             if (item && item->email && item->email->subject && item->email->subject->subj) {
00137                 DEBUG_EMAIL(("item->email->subject = %p\n", item->email->subject));
00138                 DEBUG_EMAIL(("item->email->subject->subj = %p\n", item->email->subject->subj));
00139             }
00140             if (item) {
00141                 if (item->folder && d_ptr->child && (deleted_mode == DMODE_INCLUDE || strcasecmp(item->file_as, "Deleted Items"))) {
00142                     //if this is a non-empty folder other than deleted items, we want to recurse into it
00143                     if (output_mode != OUTPUT_QUIET) printf("Processing Folder \"%s\"\n", item->file_as);
00144                     process(item, d_ptr->child);
00145 
00146                 } else if (item->contact && (item->type == PST_TYPE_CONTACT)) {
00147                     // deal with a contact
00148                     // write them to the file, one per line in this format
00149                     // Desc Name <email@address>\n
00150                     if (mode == MODE_SEPARATE) mk_separate_file(&ff);
00151                     ff.email_count++;
00152                     DEBUG_MAIN(("main: Processing Contact\n"));
00153                     if (ff.type != PST_TYPE_CONTACT) {
00154                         DEBUG_MAIN(("main: I have a contact, but the folder isn't a contacts folder. Processing anyway\n"));
00155                     }
00156                     if (contact_mode == CMODE_VCARD)
00157                         write_vcard(ff.output, item->contact, item->comment);
00158                     else
00159                         fprintf(ff.output, "%s <%s>\n", item->contact->fullname, item->contact->address1);
00160 
00161                 } else if (item->email && (item->type == PST_TYPE_NOTE || item->type == PST_TYPE_REPORT || item->type == PST_TYPE_OTHER)) {
00162                     if (mode == MODE_SEPARATE) mk_separate_file(&ff);
00163                     ff.email_count++;
00164                     DEBUG_MAIN(("main: Processing Email\n"));
00165                     if ((ff.type != PST_TYPE_NOTE) && (ff.type != PST_TYPE_REPORT) && (ff.type != PST_TYPE_OTHER)) {
00166                         DEBUG_MAIN(("main: I have an email, but the folder isn't an email folder. Processing anyway\n"));
00167                     }
00168                     write_normal_email(ff.output, ff.name, item, mode, mode_MH, &pstfile, save_rtf_body);
00169 
00170                 } else if (item->journal && (item->type == PST_TYPE_JOURNAL)) {
00171                     // deal with journal items
00172                     if (mode == MODE_SEPARATE) mk_separate_file(&ff);
00173                     ff.email_count++;
00174                     DEBUG_MAIN(("main: Processing Journal Entry\n"));
00175                     if (ff.type != PST_TYPE_JOURNAL) {
00176                         DEBUG_MAIN(("main: I have a journal entry, but the folder isn't a journal folder. Processing anyway\n"));
00177                     }
00178                     fprintf(ff.output, "BEGIN:VJOURNAL\n");
00179                     if (item->email && item->email->subject && item->email->subject->subj)
00180                         fprintf(ff.output, "SUMMARY:%s\n", pst_rfc2426_escape(item->email->subject->subj));
00181                     if (item->email && item->email->body)
00182                         fprintf(ff.output, "DESCRIPTION:%s\n", pst_rfc2426_escape(item->email->body));
00183                     if (item->journal->start)
00184                         fprintf(ff.output, "DTSTART;VALUE=DATE-TIME:%s\n", pst_rfc2445_datetime_format(item->journal->start));
00185                     fprintf(ff.output, "END:VJOURNAL\n\n");
00186 
00187                 } else if (item->appointment && (item->type == PST_TYPE_APPOINTMENT)) {
00188                     // deal with Calendar appointments
00189                     if (mode == MODE_SEPARATE) mk_separate_file(&ff);
00190                     ff.email_count++;
00191                     DEBUG_MAIN(("main: Processing Appointment Entry\n"));
00192                     if (ff.type != PST_TYPE_APPOINTMENT) {
00193                         DEBUG_MAIN(("main: I have an appointment, but folder isn't specified as an appointment type. Processing...\n"));
00194                     }
00195                     write_appointment(ff.output, item->appointment, item->email, item->create_date, item->modify_date);
00196 
00197                 } else if (item->message_store) {
00198                     // there should only be one message_store, and we have already done it
00199                     DEBUG_MAIN(("item with message store content, type %i %s folder type %i, skipping it\n", item->type, item->ascii_type, ff.type));
00200 
00201                 } else {
00202                     // these all seem to be things that MS agrees are not included in the item count
00203                     //ff.skip_count++;
00204                     DEBUG_MAIN(("main: Unknown item type %i (%s) name (%s)\n",
00205                                 item->type, item->ascii_type, item->file_as));
00206                 }
00207                 pst_freeItem(item);
00208             } else {
00209                 ff.skip_count++;
00210                 DEBUG_MAIN(("main: A NULL item was seen\n"));
00211             }
00212             d_ptr = d_ptr->next;
00213         }
00214     }
00215     close_enter_dir(&ff);
00216     DEBUG_RET();
00217 }
00218 
00219 
00220 
00221 int main(int argc, char** argv) {
00222     pst_item *item = NULL;
00223     pst_desc_ll *d_ptr;
00224     char * fname = NULL;
00225     char *d_log  = NULL;
00226     int c,x;
00227     char *temp = NULL;               //temporary char pointer
00228     prog_name = argv[0];
00229 
00230     // command-line option handling
00231     while ((c = getopt(argc, argv, "bCc:Dd:hko:qrSMVw"))!= -1) {
00232         switch (c) {
00233         case 'b':
00234             save_rtf_body = 0;
00235             break;
00236         case 'C':
00237             mode = MODE_DECSPEW;
00238             break;
00239         case 'c':
00240             if (optarg && optarg[0]=='v')
00241                 contact_mode=CMODE_VCARD;
00242             else if (optarg && optarg[0]=='l')
00243                 contact_mode=CMODE_LIST;
00244             else {
00245                 usage();
00246                 exit(0);
00247             }
00248             break;
00249         case 'D':
00250             deleted_mode = DMODE_INCLUDE;
00251             break;
00252         case 'd':
00253             d_log = optarg;
00254             break;
00255         case 'h':
00256             usage();
00257             exit(0);
00258             break;
00259         case 'V':
00260             version();
00261             exit(0);
00262             break;
00263         case 'k':
00264             mode = MODE_KMAIL;
00265             break;
00266         case 'M':
00267             mode = MODE_SEPARATE;
00268             mode_MH = 1;
00269             break;
00270         case 'o':
00271             output_dir = optarg;
00272             break;
00273         case 'q':
00274             output_mode = OUTPUT_QUIET;
00275             break;
00276         case 'r':
00277             mode = MODE_RECURSE;
00278             break;
00279         case 'S':
00280             mode = MODE_SEPARATE;
00281             break;
00282         case 'w':
00283             overwrite = 1;
00284             break;
00285         default:
00286             usage();
00287             exit(1);
00288             break;
00289         }
00290     }
00291 
00292     if (argc > optind) {
00293         fname = argv[optind];
00294     } else {
00295         usage();
00296         exit(2);
00297     }
00298 
00299     #ifdef DEBUG_ALL
00300         // force a log file
00301         if (!d_log) d_log = "readpst.log";
00302     #endif // defined DEBUG_ALL
00303     DEBUG_INIT(d_log);
00304     DEBUG_REGISTER_CLOSE();
00305     DEBUG_ENT("main");
00306 
00307     if (mode == MODE_DECSPEW) {
00308         FILE  *fp;
00309         char   buf[1024];
00310         size_t l = 0;
00311         if (NULL == (fp = fopen(fname, "rb"))) {
00312             fprintf(stderr, "Couldn't open file %s\n", fname );
00313             DEBUG_RET();
00314             return 1;
00315         }
00316 
00317         while (0 != (l = fread(buf, 1, 1024, fp))) {
00318             if (0 != pst_decrypt(0, buf, l, PST_COMP_ENCRYPT))
00319                 fprintf(stderr, "pst_decrypt() failed (I'll try to continue)\n");
00320 
00321             if (l != pst_fwrite(buf, 1, l, stdout)) {
00322                 fprintf(stderr, "Couldn't output to stdout?\n");
00323                 DEBUG_RET();
00324                 return 1;
00325             }
00326         }
00327         DEBUG_RET();
00328         return 0;
00329     }
00330 
00331     if (output_mode != OUTPUT_QUIET) printf("Opening PST file and indexes...\n");
00332 
00333     RET_DERROR(pst_open(&pstfile, fname), 1, ("Error opening File\n"));
00334     RET_DERROR(pst_load_index(&pstfile), 2, ("Index Error\n"));
00335 
00336     pst_load_extended_attributes(&pstfile);
00337 
00338     if (chdir(output_dir)) {
00339         x = errno;
00340         pst_close(&pstfile);
00341         DEBUG_RET();
00342         DIE(("main: Cannot change to output dir %s: %s\n", output_dir, strerror(x)));
00343     }
00344 
00345     if (output_mode != OUTPUT_QUIET) printf("About to start processing first record...\n");
00346 
00347     d_ptr = pstfile.d_head; // first record is main record
00348     item  = pst_parse_item(&pstfile, d_ptr);
00349     if (!item || !item->message_store) {
00350         DEBUG_RET();
00351         DIE(("main: Could not get root record\n"));
00352     }
00353 
00354     // default the file_as to the same as the main filename if it doesn't exist
00355     if (!item->file_as) {
00356         if (!(temp = strrchr(fname, '/')))
00357             if (!(temp = strrchr(fname, '\\')))
00358                 temp = fname;
00359             else
00360                 temp++; // get past the "\\"
00361         else
00362             temp++; // get past the "/"
00363         item->file_as = (char*)xmalloc(strlen(temp)+1);
00364         strcpy(item->file_as, temp);
00365         DEBUG_MAIN(("file_as was blank, so am using %s\n", item->file_as));
00366     }
00367     DEBUG_MAIN(("main: Root Folder Name: %s\n", item->file_as));
00368 
00369     d_ptr = pst_getTopOfFolders(&pstfile, item);
00370     if (!d_ptr) {
00371         DEBUG_RET();
00372         DIE(("Top of folders record not found. Cannot continue\n"));
00373     }
00374 
00375     process(item, d_ptr->child);    // do the children of TOPF
00376     pst_freeItem(item);
00377     pst_close(&pstfile);
00378     DEBUG_RET();
00379     return 0;
00380 }
00381 
00382 
00383 void write_email_body(FILE *f, char *body) {
00384     char *n = body;
00385     //  DEBUG_MAIN(("write_email_body(): \"%s\"\n", body));
00386     DEBUG_ENT("write_email_body");
00387     while (n) {
00388         if (strncmp(body, "From ", 5) == 0)
00389             fprintf(f, ">");
00390         if ((n = strchr(body, '\n'))) {
00391             n++;
00392             pst_fwrite(body, n-body, 1, f); //write just a line
00393             body = n;
00394         }
00395     }
00396     pst_fwrite(body, strlen(body), 1, f);
00397     DEBUG_RET();
00398 }
00399 
00400 
00401 char *removeCR (char *c) {
00402     // converts /r/n to /n
00403     char *a, *b;
00404     DEBUG_ENT("removeCR");
00405     a = b = c;
00406     while (*a != '\0') {
00407         *b = *a;
00408         if (*a != '\r')
00409             b++;
00410         a++;
00411     }
00412     *b = '\0';
00413     DEBUG_RET();
00414     return c;
00415 }
00416 
00417 
00418 int usage() {
00419     DEBUG_ENT("usage");
00420     version();
00421     printf("Usage: %s [OPTIONS] {PST FILENAME}\n", prog_name);
00422     printf("OPTIONS:\n");
00423     printf("\t-V\t- Version. Display program version\n");
00424     printf("\t-C\t- Decrypt (compressible encryption) the entire file and output on stdout (not typically useful)\n");
00425     printf("\t-D\t- Include deleted items in output\n");
00426     printf("\t-M\t- MH. Write emails in the MH format\n");
00427     printf("\t-S\t- Separate. Write emails in the separate format\n");
00428     printf("\t-b\t- Don't save RTF-Body attachments\n");
00429     printf("\t-c[v|l]\t- Set the Contact output mode. -cv = VCard, -cl = EMail list\n");
00430     printf("\t-d <filename> \t- Debug to file. This is a binary log. Use readpstlog to print it\n");
00431     printf("\t-h\t- Help. This screen\n");
00432     printf("\t-k\t- KMail. Output in kmail format\n");
00433     printf("\t-o <dirname>\t- Output directory to write files to. CWD is changed *after* opening pst file\n");
00434     printf("\t-q\t- Quiet. Only print error messages\n");
00435     printf("\t-r\t- Recursive. Output in a recursive format\n");
00436     printf("\t-w\t- Overwrite any output mbox files\n");
00437     DEBUG_RET();
00438     return 0;
00439 }
00440 
00441 
00442 int version() {
00443     DEBUG_ENT("version");
00444     printf("ReadPST / LibPST v%s\n", VERSION);
00445 #if BYTE_ORDER == BIG_ENDIAN
00446     printf("Big Endian implementation being used.\n");
00447 #elif BYTE_ORDER == LITTLE_ENDIAN
00448     printf("Little Endian implementation being used.\n");
00449 #else
00450 #  error "Byte order not supported by this library"
00451 #endif
00452 #ifdef __GNUC__
00453     printf("GCC %d.%d : %s %s\n", __GNUC__, __GNUC_MINOR__, __DATE__, __TIME__);
00454 #endif
00455     DEBUG_RET();
00456     return 0;
00457 }
00458 
00459 
00460 char *mk_kmail_dir(char *fname) {
00461     //change to that directory
00462     //make a directory based on OUTPUT_KMAIL_DIR_TEMPLATE
00463     //allocate space for OUTPUT_TEMPLATE and form a char* with fname
00464     //return that value
00465     char *dir, *out_name, *index;
00466     int x;
00467     DEBUG_ENT("mk_kmail_dir");
00468     if (kmail_chdir && chdir(kmail_chdir)) {
00469         x = errno;
00470         DIE(("mk_kmail_dir: Cannot change to directory %s: %s\n", kmail_chdir, strerror(x)));
00471     }
00472     dir = malloc(strlen(fname)+strlen(OUTPUT_KMAIL_DIR_TEMPLATE)+1);
00473     sprintf(dir, OUTPUT_KMAIL_DIR_TEMPLATE, fname);
00474     check_filename(dir);
00475     if (D_MKDIR(dir)) {
00476         //error occured
00477         if (errno != EEXIST) {
00478             x = errno;
00479             DIE(("mk_kmail_dir: Cannot create directory %s: %s\n", dir, strerror(x)));
00480         }
00481     }
00482     kmail_chdir = realloc(kmail_chdir, strlen(dir)+1);
00483     strcpy(kmail_chdir, dir);
00484     free (dir);
00485 
00486     //we should remove any existing indexes created by KMail, cause they might be different now
00487     index = malloc(strlen(fname)+strlen(KMAIL_INDEX)+1);
00488     sprintf(index, KMAIL_INDEX, fname);
00489     unlink(index);
00490     free(index);
00491 
00492     out_name = malloc(strlen(fname)+strlen(OUTPUT_TEMPLATE)+1);
00493     sprintf(out_name, OUTPUT_TEMPLATE, fname);
00494     DEBUG_RET();
00495     return out_name;
00496 }
00497 
00498 
00499 int close_kmail_dir() {
00500     // change ..
00501     int x;
00502     DEBUG_ENT("close_kmail_dir");
00503     if (kmail_chdir) { //only free kmail_chdir if not NULL. do not change directory
00504         free(kmail_chdir);
00505         kmail_chdir = NULL;
00506     } else {
00507         if (chdir("..")) {
00508             x = errno;
00509             DIE(("close_kmail_dir: Cannot move up dir (..): %s\n", strerror(x)));
00510         }
00511     }
00512     DEBUG_RET();
00513     return 0;
00514 }
00515 
00516 
00517 // this will create a directory by that name, then make an mbox file inside
00518 // that dir.  any subsequent dirs will be created by name, and they will
00519 // contain mbox files
00520 char *mk_recurse_dir(char *dir) {
00521     int x;
00522     char *out_name;
00523     DEBUG_ENT("mk_recurse_dir");
00524     check_filename(dir);
00525     if (D_MKDIR (dir)) {
00526         if (errno != EEXIST) { // not an error because it exists
00527             x = errno;
00528             DIE(("mk_recurse_dir: Cannot create directory %s: %s\n", dir, strerror(x)));
00529         }
00530     }
00531     if (chdir (dir)) {
00532         x = errno;
00533         DIE(("mk_recurse_dir: Cannot change to directory %s: %s\n", dir, strerror(x)));
00534     }
00535     out_name = malloc(strlen("mbox")+1);
00536     strcpy(out_name, "mbox");
00537     DEBUG_RET();
00538     return out_name;
00539 }
00540 
00541 
00542 int close_recurse_dir() {
00543     int x;
00544     DEBUG_ENT("close_recurse_dir");
00545     if (chdir("..")) {
00546         x = errno;
00547         DIE(("close_recurse_dir: Cannot go up dir (..): %s\n", strerror(x)));
00548     }
00549     DEBUG_RET();
00550     return 0;
00551 }
00552 
00553 
00554 char *mk_separate_dir(char *dir) {
00555     size_t dirsize = strlen(dir) + 10;
00556     char dir_name[dirsize];
00557     int x = 0, y = 0;
00558 
00559     DEBUG_ENT("mk_separate_dir");
00560     do {
00561         if (y == 0)
00562             snprintf(dir_name, dirsize, "%s", dir);
00563         else
00564             snprintf(dir_name, dirsize, "%s" SEP_MAIL_FILE_TEMPLATE, dir, y); // enough for 9 digits allocated above
00565 
00566         check_filename(dir_name);
00567         DEBUG_MAIN(("about to try creating %s\n", dir_name));
00568         if (D_MKDIR(dir_name)) {
00569             if (errno != EEXIST) { // if there is an error, and it doesn't already exist
00570                 x = errno;
00571                 DIE(("mk_separate_dir: Cannot create directory %s: %s\n", dir, strerror(x)));
00572             }
00573         } else {
00574             break;
00575         }
00576         y++;
00577     } while (overwrite == 0);
00578 
00579     if (chdir(dir_name)) {
00580         x = errno;
00581         DIE(("mk_separate_dir: Cannot change to directory %s: %s\n", dir, strerror(x)));
00582     }
00583 
00584     if (overwrite) {
00585         // we should probably delete all files from this directory
00586 #if !defined(WIN32) && !defined(__CYGWIN__)
00587         DIR * sdir = NULL;
00588         struct dirent *dirent = NULL;
00589         struct stat filestat;
00590         if (!(sdir = opendir("./"))) {
00591             WARN(("mk_separate_dir: Cannot open dir \"%s\" for deletion of old contents\n", "./"));
00592         } else {
00593             while ((dirent = readdir(sdir))) {
00594                 if (lstat(dirent->d_name, &filestat) != -1)
00595                     if (S_ISREG(filestat.st_mode)) {
00596                         if (unlink(dirent->d_name)) {
00597                             y = errno;
00598                             DIE(("mk_separate_dir: unlink returned error on file %s: %s\n", dirent->d_name, strerror(y)));
00599                         }
00600                     }
00601             }
00602         }
00603 #endif
00604     }
00605 
00606     // we don't return a filename here cause it isn't necessary.
00607     DEBUG_RET();
00608     return NULL;
00609 }
00610 
00611 
00612 int close_separate_dir() {
00613     int x;
00614     DEBUG_ENT("close_separate_dir");
00615     if (chdir("..")) {
00616         x = errno;
00617         DIE(("close_separate_dir: Cannot go up dir (..): %s\n", strerror(x)));
00618     }
00619     DEBUG_RET();
00620     return 0;
00621 }
00622 
00623 
00624 int mk_separate_file(struct file_ll *f) {
00625     const int name_offset = 1;
00626     DEBUG_ENT("mk_separate_file");
00627     DEBUG_MAIN(("opening next file to save email\n"));
00628     if (f->email_count > 999999999) { // bigger than nine 9's
00629         DIE(("mk_separate_file: The number of emails in this folder has become too high to handle"));
00630     }
00631     sprintf(f->name, SEP_MAIL_FILE_TEMPLATE, f->email_count + name_offset);
00632     if (f->output) fclose(f->output);
00633     f->output = NULL;
00634     check_filename(f->name);
00635     if (!(f->output = fopen(f->name, "w"))) {
00636         DIE(("mk_separate_file: Cannot open file to save email \"%s\"\n", f->name));
00637     }
00638     DEBUG_RET();
00639     return 0;
00640 }
00641 
00642 
00643 char *my_stristr(char *haystack, char *needle) {
00644     // my_stristr varies from strstr in that its searches are case-insensitive
00645     char *x=haystack, *y=needle, *z = NULL;
00646     DEBUG_ENT("my_stristr");
00647     if (!haystack || !needle) {
00648         DEBUG_RET();
00649         return NULL;
00650     }
00651     while (*y != '\0' && *x != '\0') {
00652         if (tolower(*y) == tolower(*x)) {
00653             // move y on one
00654             y++;
00655             if (!z) {
00656                 z = x; // store first position in haystack where a match is made
00657             }
00658         } else {
00659             y = needle; // reset y to the beginning of the needle
00660             z = NULL; // reset the haystack storage point
00661         }
00662         x++; // advance the search in the haystack
00663     }
00664     DEBUG_RET();
00665     // If the haystack ended before our search finished, it's not a match.
00666     if (*y != '\0') return NULL;
00667     return z;
00668 }
00669 
00670 
00671 void check_filename(char *fname) {
00672     char *t = fname;
00673     DEBUG_ENT("check_filename");
00674     if (!t) {
00675         DEBUG_RET();
00676         return;
00677     }
00678     while ((t = strpbrk(t, "/\\:"))) {
00679         // while there are characters in the second string that we don't want
00680         *t = '_'; //replace them with an underscore
00681     }
00682     DEBUG_RET();
00683 }
00684 
00685 
00686 // The sole purpose of this function is to bypass the pseudo-header prologue
00687 // that Microsoft Outlook inserts at the beginning of the internet email
00688 // headers for emails stored in their "Personal Folders" files.
00689 char *skip_header_prologue(char *headers) {
00690     const char *bad = "Microsoft Mail Internet Headers";
00691     if (strncmp(headers, bad, strlen(bad)) == 0) {
00692         // Found the offensive header prologue
00693         char *pc = strchr(headers, '\n');
00694         return pc + 1;
00695     }
00696     return headers;
00697 }
00698 
00699 
00700 void write_separate_attachment(char f_name[], pst_item_attach* current_attach, int attach_num, pst_file* pst)
00701 {
00702     FILE *fp = NULL;
00703     int x = 0;
00704     char *temp = NULL;
00705 
00706     // If there is a long filename (filename2) use that, otherwise
00707     // use the 8.3 filename (filename1)
00708     char *attach_filename = (current_attach->filename2) ? current_attach->filename2
00709                                                         : current_attach->filename1;
00710     DEBUG_ENT("write_separate_attachment");
00711 
00712     check_filename(f_name);
00713     if (!attach_filename) {
00714         // generate our own (dummy) filename for the attachement
00715         temp = xmalloc(strlen(f_name)+15);
00716         sprintf(temp, "%s-attach%i", f_name, attach_num);
00717     } else {
00718         // have an attachment name, make sure it's unique
00719         temp = xmalloc(strlen(f_name)+strlen(attach_filename)+15);
00720         do {
00721             if (fp) fclose(fp);
00722             if (x == 0)
00723                 sprintf(temp, "%s-%s", f_name, attach_filename);
00724             else
00725                 sprintf(temp, "%s-%s-%i", f_name, attach_filename, x);
00726         } while ((fp = fopen(temp, "r")) && ++x < 99999999);
00727         if (x > 99999999) {
00728             DIE(("error finding attachment name. exhausted possibilities to %s\n", temp));
00729         }
00730     }
00731     DEBUG_EMAIL(("Saving attachment to %s\n", temp));
00732     if (!(fp = fopen(temp, "w"))) {
00733         WARN(("write_separate_attachment: Cannot open attachment save file \"%s\"\n", temp));
00734     } else {
00735         if (current_attach->data)
00736             pst_fwrite(current_attach->data, 1, current_attach->size, fp);
00737         else {
00738             (void)pst_attach_to_file(pst, current_attach, fp);
00739         }
00740         fclose(fp);
00741     }
00742     if (temp) free(temp);
00743     DEBUG_RET();
00744 }
00745 
00746 
00747 void write_inline_attachment(FILE* f_output, pst_item_attach* current_attach, char boundary[], pst_file* pst)
00748 {
00749     char *enc = NULL; // base64 encoded attachment
00750     DEBUG_ENT("write_inline_attachment");
00751     DEBUG_EMAIL(("Attachment Size is %i\n", current_attach->size));
00752     DEBUG_EMAIL(("Attachment Pointer is %p\n", current_attach->data));
00753     if (current_attach->data) {
00754         enc = base64_encode (current_attach->data, current_attach->size);
00755         if (!enc) {
00756             DEBUG_EMAIL(("ERROR base64_encode returned NULL. Must have failed\n"));
00757             DEBUG_RET();
00758             return;
00759         }
00760     }
00761     if (boundary) {
00762         char *attach_filename;
00763         fprintf(f_output, "\n--%s\n", boundary);
00764         if (!current_attach->mimetype) {
00765             fprintf(f_output, "Content-type: %s\n", MIME_TYPE_DEFAULT);
00766         } else {
00767             fprintf(f_output, "Content-type: %s\n", current_attach->mimetype);
00768         }
00769         fprintf(f_output, "Content-transfer-encoding: base64\n");
00770         // If there is a long filename (filename2) use that, otherwise
00771         // use the 8.3 filename (filename1)
00772         if (current_attach->filename2) {
00773             attach_filename = current_attach->filename2;
00774         } else {
00775             attach_filename = current_attach->filename1;
00776         }
00777         if (!attach_filename) {
00778             fprintf(f_output, "Content-Disposition: inline\n\n");
00779         } else {
00780             fprintf(f_output, "Content-Disposition: attachment; filename=\"%s\"\n\n", attach_filename);
00781         }
00782     }
00783     if (current_attach->data) {
00784         pst_fwrite(enc, 1, strlen(enc), f_output);
00785         DEBUG_EMAIL(("Attachment Size after encoding is %i\n", strlen(enc)));
00786         free(enc);  // caught by valgrind
00787     } else {
00788         (void)pst_attach_to_file_base64(pst, current_attach, f_output);
00789     }
00790     fprintf(f_output, "\n\n");
00791     DEBUG_RET();
00792 }
00793 
00794 
00795 void write_normal_email(FILE* f_output, char f_name[], pst_item* item, int mode, int mode_MH, pst_file* pst, int save_rtf)
00796 {
00797     char *boundary = NULL;      // the boundary marker between multipart sections
00798     int boundary_created = 0;   // we have not (yet) created a new boundary
00799     char *temp = NULL;
00800     int attach_num, base64_body = 0;
00801     time_t em_time;
00802     char *c_time;
00803     pst_item_attach* current_attach;
00804     int has_from, has_subject, has_to, has_cc, has_bcc, has_date;
00805     has_from = has_subject = has_to = has_cc = has_bcc = has_date = 0;
00806     DEBUG_ENT("write_normal_email");
00807 
00808     // convert the sent date if it exists, or set it to a fixed date
00809     if (item->email->sent_date) {
00810         em_time = fileTimeToUnixTime(item->email->sent_date, 0);
00811         c_time = ctime(&em_time);
00812         if (c_time)
00813             c_time[strlen(c_time)-1] = '\0'; //remove end \n
00814         else
00815             c_time = "Fri Dec 28 12:06:21 2001";
00816     } else
00817         c_time= "Fri Dec 28 12:06:21 2001";
00818 
00819     // we will always look at the header to discover some stuff
00820     if (item->email->header ) {
00821         char *b1, *b2;
00822         // see if there is a boundary variable there
00823         // this search MUST be made case insensitive (DONE).
00824         // Also, we should check to find out if we are looking
00825         // at the boundary associated with content-type, and that
00826         // the content type really is multipart
00827 
00828         removeCR(item->email->header);
00829 
00830         if ((b2 = my_stristr(item->email->header, "boundary="))) {
00831             int len;
00832             b2 += strlen("boundary="); // move boundary to first char of marker
00833 
00834             if (*b2 == '"') {
00835                 b2++;
00836                 b1 = strchr(b2, '"'); // find terminating quote
00837             } else {
00838                 b1 = b2;
00839                 while (isgraph(*b1)) // find first char that isn't part of boundary
00840                     b1++;
00841             }
00842             len = b1 - b2;
00843             boundary = malloc(len+1);   //malloc that length
00844             strncpy(boundary, b2, len); // copy boundary to another variable
00845             boundary[len] = '\0';
00846             b1 = b2 = boundary;
00847             while (*b2 != '\0') { // remove any CRs and Tabs
00848                 if (*b2 != '\n' && *b2 != '\r' && *b2 != '\t') {
00849                     *b1 = *b2;
00850                     b1++;
00851                 }
00852                 b2++;
00853             }
00854             *b1 = '\0';
00855 
00856             DEBUG_EMAIL(("Found boundary of - %s\n", boundary));
00857         } else {
00858             DEBUG_EMAIL(("boundary not found in header\n"));
00859         }
00860 
00861         // also possible to set 7bit encoding detection here.
00862         if ((b2 = my_stristr(item->email->header, "Content-Transfer-Encoding:"))) {
00863             if ((b2 = strchr(b2, ':'))) {
00864                 b2++; // skip to the : at the end of the string
00865 
00866                 while (*b2 == ' ' || *b2 == '\t')
00867                     b2++;
00868                 if (pst_strincmp(b2, "base64", 6)==0) {
00869                     DEBUG_EMAIL(("body is base64 encoded\n"));
00870                     base64_body = 1;
00871                 }
00872             } else {
00873                 DEBUG_WARN(("found a ':' during the my_stristr, but not after that..\n"));
00874             }
00875         }
00876 
00877         // Check if the header block has all the necessary headers.
00878         if (my_stristr(item->email->header, "\nFrom:") || (strncasecmp(item->email->header, "From: ", 6) == 0) || my_stristr(item->email->header, "\nX-From:")) {
00879             DEBUG_EMAIL(("header block has From header\n"));
00880             has_from = 1;
00881         }
00882         if (my_stristr(item->email->header, "\nTo:") || (strncasecmp(item->email->header, "To: ", 4) == 0)) {
00883             DEBUG_EMAIL(("header block has To header\n"));
00884             has_to = 1;
00885         }
00886         if (my_stristr(item->email->header, "\nSubject:") || (strncasecmp(item->email->header, "Subject: ", 9) == 0)) {
00887             DEBUG_EMAIL(("header block has Subject header\n"));
00888             has_subject = 1;
00889         }
00890         if (my_stristr(item->email->header, "\nDate:") || (strncasecmp(item->email->header, "Date: ", 6) == 0)) {
00891             DEBUG_EMAIL(("header block has Date header\n"));
00892             has_date = 1;
00893         }
00894         if (my_stristr(item->email->header, "\nCC:") || (strncasecmp(item->email->header, "CC: ", 4) == 0)) {
00895             DEBUG_EMAIL(("header block has CC header\n"));
00896             has_cc = 1;
00897         }
00898         if (my_stristr(item->email->header, "\nBCC:") || (strncasecmp(item->email->header, "BCC: ", 5) == 0)) {
00899             DEBUG_EMAIL(("header block has BCC header\n"));
00900             has_bcc = 1;
00901         }
00902     }
00903 
00904     if (!boundary && (item->attach || (item->email->body && item->email->htmlbody)
00905                  || item->email->rtf_compressed || item->email->encrypted_body
00906                  || item->email->encrypted_htmlbody)) {
00907         // we need to create a boundary here.
00908         DEBUG_EMAIL(("must create own boundary. oh dear.\n"));
00909         boundary = malloc(50 * sizeof(char)); // allow 50 chars for boundary
00910         boundary[0] = '\0';
00911         sprintf(boundary, "--boundary-LibPST-iamunique-%i_-_-", rand());
00912         DEBUG_EMAIL(("created boundary is %s\n", boundary));
00913         boundary_created = 1;
00914     }
00915 
00916     DEBUG_EMAIL(("About to print Header\n"));
00917 
00918     if (item && item->email && item->email->subject && item->email->subject->subj) {
00919         DEBUG_EMAIL(("item->email->subject->subj = %s\n", item->email->subject->subj));
00920     }
00921 
00922     if (item->email->header) {
00923         int len;
00924         char *soh = NULL;  // real start of headers.
00925 
00926         // some of the headers we get from the file are not properly defined.
00927         // they can contain some email stuff too. We will cut off the header
00928         // when we see a \n\n or \r\n\r\n
00929         removeCR(item->email->header);
00930         temp = strstr(item->email->header, "\n\n");
00931 
00932         if (temp) {
00933             DEBUG_EMAIL(("Found body text in header\n"));
00934             temp[1] = '\0'; // stop after first \n
00935         }
00936 
00937         // Write out any fields that weren't included in the header.
00938         if (!has_from) {
00939             temp = item->email->outlook_sender;
00940             if (!temp) temp = "";
00941             fprintf(f_output, "From: \"%s\" <%s>\n", item->email->outlook_sender_name, temp);
00942         }
00943 
00944         if (!has_subject) {
00945             if (item->email->subject && item->email->subject->subj) {
00946                 fprintf(f_output, "Subject: %s\n", item->email->subject->subj);
00947             } else {
00948                 fprintf(f_output, "Subject: \n");
00949             }
00950         }
00951 
00952         if (!has_to && item->email->sentto_address) {
00953             fprintf(f_output, "To: %s\n", item->email->sentto_address);
00954         }
00955 
00956         if (!has_cc && item->email->cc_address) {
00957             fprintf(f_output, "Cc: %s\n", item->email->cc_address);
00958         }
00959 
00960         if (!has_bcc && item->email->bcc_address) {
00961             fprintf(f_output, "Bcc: %s\n", item->email->bcc_address);
00962         }
00963 
00964         if (!has_date && item->email->sent_date) {
00965             char c_time[C_TIME_SIZE];
00966             strftime(c_time, C_TIME_SIZE, "%a, %d %b %Y %H:%M:%S %z", gmtime(&em_time));
00967             fprintf(f_output, "Date: %s\n", c_time);
00968         }
00969 
00970         // Now, write out the header...
00971         soh = skip_header_prologue(item->email->header);
00972         if (mode != MODE_SEPARATE) {
00973             // don't put rubbish in if we are doing separate
00974             if (strncmp(soh, "X-From_: ", 9) == 0 ) {
00975                 fputs("From ", f_output);
00976                 soh += 9;
00977             } else
00978                 fprintf(f_output, "From \"%s\" %s\n", item->email->outlook_sender_name, c_time);
00979         }
00980         fprintf(f_output, "%s", soh);
00981         len = strlen(soh);
00982         if (!len || (soh[len-1] != '\n')) fprintf(f_output, "\n");
00983 
00984     } else {
00985         //make up our own headers
00986         if (mode != MODE_SEPARATE) {
00987             // don't want this first line for this mode
00988             if (item->email->outlook_sender_name) {
00989                 temp = item->email->outlook_sender_name;
00990             } else {
00991                 temp = "(readpst_null)";
00992             }
00993             fprintf(f_output, "From \"%s\" %s\n", temp, c_time);
00994         }
00995 
00996         temp = item->email->outlook_sender;
00997         if (!temp) temp = "";
00998         fprintf(f_output, "From: \"%s\" <%s>\n", item->email->outlook_sender_name, temp);
00999 
01000         if (item->email->subject && item->email->subject->subj) {
01001             fprintf(f_output, "Subject: %s\n", item->email->subject->subj);
01002         } else {
01003             fprintf(f_output, "Subject: \n");
01004         }
01005 
01006         if (item->email->sentto_address) {
01007             fprintf(f_output, "To: %s\n", item->email->sentto_address);
01008         }
01009 
01010         if (item->email->cc_address) {
01011             fprintf(f_output, "Cc: %s\n", item->email->cc_address);
01012         }
01013 
01014         if (item->email->sent_date) {
01015             char c_time[C_TIME_SIZE];
01016             strftime(c_time, C_TIME_SIZE, "%a, %d %b %Y %H:%M:%S %z", gmtime(&em_time));
01017             fprintf(f_output, "Date: %s\n", c_time);
01018         }
01019     }
01020 
01021     fprintf(f_output, "MIME-Version: 1.0\n");
01022     if (boundary && boundary_created) {
01023         // if we created the boundary, then it has NOT already been printed
01024         // in the headers above.
01025         if (item->attach) {
01026             // write the boundary stuff if we have attachments
01027             fprintf(f_output, "Content-type: multipart/mixed;\n\tboundary=\"%s\"\n", boundary);
01028         } else if (boundary) {
01029             // else if we have multipart/alternative then tell it so
01030             fprintf(f_output, "Content-type: multipart/alternative;\n\tboundary=\"%s\"\n", boundary);
01031         } else if (item->email->htmlbody) {
01032             fprintf(f_output, "Content-type: text/html\n");
01033         }
01034     }
01035     fprintf(f_output, "\n");    // start the body
01036     DEBUG_EMAIL(("About to print Body\n"));
01037 
01038     if (item->email->body) {
01039         if (boundary) {
01040             fprintf(f_output, "\n--%s\n", boundary);
01041             fprintf(f_output, "Content-type: text/plain\n");
01042             if (base64_body)
01043                 fprintf(f_output, "Content-Transfer-Encoding: base64\n");
01044             fprintf(f_output, "\n");
01045         }
01046         removeCR(item->email->body);
01047         if (base64_body) {
01048             char *enc = base64_encode(item->email->body, strlen(item->email->body));
01049             if (enc) {
01050                 write_email_body(f_output, enc);
01051                 free(enc);
01052             }
01053         }
01054         else {
01055             write_email_body(f_output, item->email->body);
01056         }
01057     }
01058 
01059     if (item->email->htmlbody) {
01060         if (boundary) {
01061             fprintf(f_output, "\n--%s\n", boundary);
01062             fprintf(f_output, "Content-type: text/html\n");
01063             if (base64_body) fprintf(f_output, "Content-Transfer-Encoding: base64\n");
01064             fprintf(f_output, "\n");
01065         }
01066         removeCR(item->email->htmlbody);
01067         if (base64_body) {
01068             char *enc = base64_encode(item->email->htmlbody, strlen(item->email->htmlbody));
01069             if (enc) {
01070                 write_email_body(f_output, enc);
01071                 free(enc);
01072             }
01073         }
01074         else {
01075             write_email_body(f_output, item->email->htmlbody);
01076         }
01077     }
01078 
01079     if (item->email->rtf_compressed && save_rtf) {
01080       //int32_t tester;
01081         DEBUG_EMAIL(("Adding RTF body as attachment\n"));
01082         current_attach = (pst_item_attach*)xmalloc(sizeof(pst_item_attach));
01083         memset(current_attach, 0, sizeof(pst_item_attach));
01084         current_attach->next = item->attach;
01085         item->attach = current_attach;
01086         current_attach->data = lzfu_decompress(item->email->rtf_compressed, item->email->rtf_compressed_size, &current_attach->size);
01087         current_attach->filename2 = xmalloc(strlen(RTF_ATTACH_NAME)+2);
01088         strcpy(current_attach->filename2, RTF_ATTACH_NAME);
01089         current_attach->mimetype = xmalloc(strlen(RTF_ATTACH_TYPE)+2);
01090         strcpy(current_attach->mimetype, RTF_ATTACH_TYPE);
01091       //memcpy(&tester, item->email->rtf_compressed+sizeof(int32_t), sizeof(int32_t));
01092       //LE32_CPU(tester);
01093       //printf("lz produced %d bytes, rtf claims %d bytes\n", current_attach->size, tester);
01094     }
01095 
01096     if (item->email->encrypted_body || item->email->encrypted_htmlbody) {
01097         // if either the body or htmlbody is encrypted, add them as attachments
01098         if (item->email->encrypted_body) {
01099             DEBUG_EMAIL(("Adding Encrypted Body as attachment\n"));
01100             current_attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach));
01101             memset(current_attach, 0, sizeof(pst_item_attach));
01102             current_attach->next = item->attach;
01103             item->attach = current_attach;
01104             current_attach->data = item->email->encrypted_body;
01105             current_attach->size = item->email->encrypted_body_size;
01106             item->email->encrypted_body = NULL;
01107         }
01108 
01109         if (item->email->encrypted_htmlbody) {
01110             DEBUG_EMAIL(("Adding encrypted HTML body as attachment\n"));
01111             current_attach = (pst_item_attach*) xmalloc(sizeof(pst_item_attach));
01112             memset(current_attach, 0, sizeof(pst_item_attach));
01113             current_attach->next = item->attach;
01114             item->attach = current_attach;
01115             current_attach->data = item->email->encrypted_htmlbody;
01116             current_attach->size = item->email->encrypted_htmlbody_size;
01117             item->email->encrypted_htmlbody = NULL;
01118         }
01119         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");
01120     }
01121 
01122     // attachments
01123     attach_num = 0;
01124     for (current_attach = item->attach; current_attach; current_attach = current_attach->next) {
01125         DEBUG_EMAIL(("Attempting Attachment encoding\n"));
01126         if (!current_attach->data) {
01127             DEBUG_EMAIL(("Data of attachment is NULL!. Size is supposed to be %i\n", current_attach->size));
01128         }
01129         if (mode == MODE_SEPARATE && !mode_MH)
01130             write_separate_attachment(f_name, current_attach, ++attach_num, pst);
01131         else
01132             write_inline_attachment(f_output, current_attach, boundary, pst);
01133     }
01134     if (mode != MODE_SEPARATE) { /* do not add a boundary after the last attachment for mode_MH */
01135         DEBUG_EMAIL(("Writing buffer between emails\n"));
01136         if (boundary) fprintf(f_output, "\n--%s--\n", boundary);
01137         fprintf(f_output, "\n\n");
01138     }
01139     if (boundary) free (boundary);
01140     DEBUG_RET();
01141 }
01142 
01143 
01144 void write_vcard(FILE* f_output, pst_item_contact* contact, char comment[])
01145 {
01146     // We can only call rfc escape once per printf, since the second call
01147     // may free the buffer returned by the first call.
01148     // I had tried to place those into a single printf - Carl.
01149 
01150     DEBUG_ENT("write_vcard");
01151     // the specification I am following is (hopefully) RFC2426 vCard Mime Directory Profile
01152     fprintf(f_output, "BEGIN:VCARD\n");
01153     fprintf(f_output, "FN:%s\n", pst_rfc2426_escape(contact->fullname));
01154 
01155     //fprintf(f_output, "N:%s;%s;%s;%s;%s\n",
01156     fprintf(f_output, "N:%s;", (!contact->surname)             ? "" : pst_rfc2426_escape(contact->surname));
01157     fprintf(f_output, "%s;",   (!contact->first_name)          ? "" : pst_rfc2426_escape(contact->first_name));
01158     fprintf(f_output, "%s;",   (!contact->middle_name)         ? "" : pst_rfc2426_escape(contact->middle_name));
01159     fprintf(f_output, "%s;",   (!contact->display_name_prefix) ? "" : pst_rfc2426_escape(contact->display_name_prefix));
01160     fprintf(f_output, "%s\n",  (!contact->suffix)              ? "" : pst_rfc2426_escape(contact->suffix));
01161 
01162     if (contact->nickname)
01163         fprintf(f_output, "NICKNAME:%s\n", pst_rfc2426_escape(contact->nickname));
01164     if (contact->address1)
01165         fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address1));
01166     if (contact->address2)
01167         fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address2));
01168     if (contact->address3)
01169         fprintf(f_output, "EMAIL:%s\n", pst_rfc2426_escape(contact->address3));
01170     if (contact->birthday)
01171         fprintf(f_output, "BDAY:%s\n", pst_rfc2425_datetime_format(contact->birthday));
01172 
01173     if (contact->home_address) {
01174         //fprintf(f_output, "ADR;TYPE=home:%s;%s;%s;%s;%s;%s;%s\n",
01175         fprintf(f_output, "ADR;TYPE=home:%s;",  (!contact->home_po_box)      ? "" : pst_rfc2426_escape(contact->home_po_box));
01176         fprintf(f_output, "%s;",                ""); // extended Address
01177         fprintf(f_output, "%s;",                (!contact->home_street)      ? "" : pst_rfc2426_escape(contact->home_street));
01178         fprintf(f_output, "%s;",                (!contact->home_city)        ? "" : pst_rfc2426_escape(contact->home_city));
01179         fprintf(f_output, "%s;",                (!contact->home_state)       ? "" : pst_rfc2426_escape(contact->home_state));
01180         fprintf(f_output, "%s;",                (!contact->home_postal_code) ? "" : pst_rfc2426_escape(contact->home_postal_code));
01181         fprintf(f_output, "%s\n",               (!contact->home_country)     ? "" : pst_rfc2426_escape(contact->home_country));
01182         fprintf(f_output, "LABEL;TYPE=home:%s\n", pst_rfc2426_escape(contact->home_address));
01183     }
01184 
01185     if (contact->business_address) {
01186         //fprintf(f_output, "ADR;TYPE=work:%s;%s;%s;%s;%s;%s;%s\n",
01187         fprintf(f_output, "ADR;TYPE=work:%s;",  (!contact->business_po_box)      ? "" : pst_rfc2426_escape(contact->business_po_box));
01188         fprintf(f_output, "%s;",                ""); // extended Address
01189         fprintf(f_output, "%s;",                (!contact->business_street)      ? "" : pst_rfc2426_escape(contact->business_street));
01190         fprintf(f_output, "%s;",                (!contact->business_city)        ? "" : pst_rfc2426_escape(contact->business_city));
01191         fprintf(f_output, "%s;",                (!contact->business_state)       ? "" : pst_rfc2426_escape(contact->business_state));
01192         fprintf(f_output, "%s;",                (!contact->business_postal_code) ? "" : pst_rfc2426_escape(contact->business_postal_code));
01193         fprintf(f_output, "%s\n",               (!contact->business_country)     ? "" : pst_rfc2426_escape(contact->business_country));
01194         fprintf(f_output, "LABEL;TYPE=work:%s\n", pst_rfc2426_escape(contact->business_address));
01195     }
01196 
01197     if (contact->other_address) {
01198         //fprintf(f_output, "ADR;TYPE=postal:%s;%s;%s;%s;%s;%s;%s\n",
01199         fprintf(f_output, "ADR;TYPE=postal:%s;",(!contact->other_po_box)       ? "" : pst_rfc2426_escape(contact->other_po_box));
01200         fprintf(f_output, "%s;",                ""); // extended Address
01201         fprintf(f_output, "%s;",                (!contact->other_street)       ? "" : pst_rfc2426_escape(contact->other_street));
01202         fprintf(f_output, "%s;",                (!contact->other_city)         ? "" : pst_rfc2426_escape(contact->other_city));
01203         fprintf(f_output, "%s;",                (!contact->other_state)        ? "" : pst_rfc2426_escape(contact->other_state));
01204         fprintf(f_output, "%s;",                (!contact->other_postal_code)  ? "" : pst_rfc2426_escape(contact->other_postal_code));
01205         fprintf(f_output, "%s\n",               (!contact->other_country)      ? "" : pst_rfc2426_escape(contact->other_country));
01206         fprintf(f_output, "LABEL;TYPE=postal:%s\n", pst_rfc2426_escape(contact->other_address));
01207     }
01208 
01209     if (contact->business_fax)      fprintf(f_output, "TEL;TYPE=work,fax:%s\n",         pst_rfc2426_escape(contact->business_fax));
01210     if (contact->business_phone)    fprintf(f_output, "TEL;TYPE=work,voice:%s\n",       pst_rfc2426_escape(contact->business_phone));
01211     if (contact->business_phone2)   fprintf(f_output, "TEL;TYPE=work,voice:%s\n",       pst_rfc2426_escape(contact->business_phone2));
01212     if (contact->car_phone)         fprintf(f_output, "TEL;TYPE=car,voice:%s\n",        pst_rfc2426_escape(contact->car_phone));
01213     if (contact->home_fax)          fprintf(f_output, "TEL;TYPE=home,fax:%s\n",         pst_rfc2426_escape(contact->home_fax));
01214     if (contact->home_phone)        fprintf(f_output, "TEL;TYPE=home,voice:%s\n",       pst_rfc2426_escape(contact->home_phone));
01215     if (contact->home_phone2)       fprintf(f_output, "TEL;TYPE=home,voice:%s\n",       pst_rfc2426_escape(contact->home_phone2));
01216     if (contact->isdn_phone)        fprintf(f_output, "TEL;TYPE=isdn:%s\n",             pst_rfc2426_escape(contact->isdn_phone));
01217     if (contact->mobile_phone)      fprintf(f_output, "TEL;TYPE=cell,voice:%s\n",       pst_rfc2426_escape(contact->mobile_phone));
01218     if (contact->other_phone)       fprintf(f_output, "TEL;TYPE=msg:%s\n",              pst_rfc2426_escape(contact->other_phone));
01219     if (contact->pager_phone)       fprintf(f_output, "TEL;TYPE=pager:%s\n",            pst_rfc2426_escape(contact->pager_phone));
01220     if (contact->primary_fax)       fprintf(f_output, "TEL;TYPE=fax,pref:%s\n",         pst_rfc2426_escape(contact->primary_fax));
01221     if (contact->primary_phone)     fprintf(f_output, "TEL;TYPE=phone,pref:%s\n",       pst_rfc2426_escape(contact->primary_phone));
01222     if (contact->radio_phone)       fprintf(f_output, "TEL;TYPE=pcs:%s\n",              pst_rfc2426_escape(contact->radio_phone));
01223     if (contact->telex)             fprintf(f_output, "TEL;TYPE=bbs:%s\n",              pst_rfc2426_escape(contact->telex));
01224     if (contact->job_title)         fprintf(f_output, "TITLE:%s\n",                     pst_rfc2426_escape(contact->job_title));
01225     if (contact->profession)        fprintf(f_output, "ROLE:%s\n",                      pst_rfc2426_escape(contact->profession));
01226     if (contact->assistant_name || contact->assistant_phone) {
01227         fprintf(f_output, "AGENT:BEGIN:VCARD\n");
01228         if (contact->assistant_name)    fprintf(f_output, "FN:%s\n",                    pst_rfc2426_escape(contact->assistant_name));
01229         if (contact->assistant_phone)   fprintf(f_output, "TEL:%s\n",                   pst_rfc2426_escape(contact->assistant_phone));
01230     }
01231     if (contact->company_name)      fprintf(f_output, "ORG:%s\n",                       pst_rfc2426_escape(contact->company_name));
01232     if (comment)                    fprintf(f_output, "NOTE:%s\n",                      pst_rfc2426_escape(comment));
01233 
01234     fprintf(f_output, "VERSION: 3.0\n");
01235     fprintf(f_output, "END:VCARD\n\n");
01236     DEBUG_RET();
01237 }
01238 
01239 
01240 void write_appointment(FILE* f_output, pst_item_appointment* appointment,
01241                pst_item_email* email, FILETIME* create_date, FILETIME* modify_date)
01242 {
01243     fprintf(f_output, "BEGIN:VEVENT\n");
01244     if (create_date)
01245         fprintf(f_output, "CREATED:%s\n",
01246             pst_rfc2445_datetime_format(create_date));
01247     if (modify_date)
01248         fprintf(f_output, "LAST-MOD:%s\n",
01249             pst_rfc2445_datetime_format(modify_date));
01250     if (email && email->subject)
01251         fprintf(f_output, "SUMMARY:%s\n",
01252             pst_rfc2426_escape(email->subject->subj));
01253     if (email && email->body)
01254         fprintf(f_output, "DESCRIPTION:%s\n",
01255             pst_rfc2426_escape(email->body));
01256     if (appointment && appointment->start)
01257         fprintf(f_output, "DTSTART;VALUE=DATE-TIME:%s\n",
01258             pst_rfc2445_datetime_format(appointment->start));
01259     if (appointment && appointment->end)
01260         fprintf(f_output, "DTEND;VALUE=DATE-TIME:%s\n",
01261             pst_rfc2445_datetime_format(appointment->end));
01262     if (appointment && appointment->location)
01263         fprintf(f_output, "LOCATION:%s\n",
01264             pst_rfc2426_escape(appointment->location));
01265     if (appointment) {
01266         switch (appointment->showas) {
01267             case PST_FREEBUSY_TENTATIVE:
01268                 fprintf(f_output, "STATUS:TENTATIVE\n");
01269                 break;
01270             case PST_FREEBUSY_FREE:
01271                 // mark as transparent and as confirmed
01272                 fprintf(f_output, "TRANSP:TRANSPARENT\n");
01273             case PST_FREEBUSY_BUSY:
01274             case PST_FREEBUSY_OUT_OF_OFFICE:
01275                 fprintf(f_output, "STATUS:CONFIRMED\n");
01276                 break;
01277         }
01278         switch (appointment->label) {
01279             case PST_APP_LABEL_NONE:
01280                 fprintf(f_output, "CATEGORIES:NONE\n");
01281                 break;
01282             case PST_APP_LABEL_IMPORTANT:
01283                 fprintf(f_output, "CATEGORIES:IMPORTANT\n");
01284                 break;
01285             case PST_APP_LABEL_BUSINESS:
01286                 fprintf(f_output, "CATEGORIES:BUSINESS\n");
01287                 break;
01288             case PST_APP_LABEL_PERSONAL:
01289                 fprintf(f_output, "CATEGORIES:PERSONAL\n");
01290                 break;
01291             case PST_APP_LABEL_VACATION:
01292                 fprintf(f_output, "CATEGORIES:VACATION\n");
01293                 break;
01294             case PST_APP_LABEL_MUST_ATTEND:
01295                 fprintf(f_output, "CATEGORIES:MUST-ATTEND\n");
01296                 break;
01297             case PST_APP_LABEL_TRAVEL_REQ:
01298                 fprintf(f_output, "CATEGORIES:TRAVEL-REQUIRED\n");
01299                 break;
01300             case PST_APP_LABEL_NEEDS_PREP:
01301                 fprintf(f_output, "CATEGORIES:NEEDS-PREPARATION\n");
01302                 break;
01303             case PST_APP_LABEL_BIRTHDAY:
01304                 fprintf(f_output, "CATEGORIES:BIRTHDAY\n");
01305                 break;
01306             case PST_APP_LABEL_ANNIVERSARY:
01307                 fprintf(f_output, "CATEGORIES:ANNIVERSARY\n");
01308                 break;
01309             case PST_APP_LABEL_PHONE_CALL:
01310                 fprintf(f_output, "CATEGORIES:PHONE-CALL\n");
01311                 break;
01312         }
01313     }
01314     fprintf(f_output, "END:VEVENT\n\n");
01315 }
01316 
01317 
01318 void create_enter_dir(struct file_ll* f, pst_item *item)
01319 {
01320     f->email_count  = 0;
01321     f->skip_count   = 0;
01322     f->type         = item->type;
01323     f->stored_count = (item->folder) ? item->folder->email_count : 0;
01324 
01325     DEBUG_ENT("create_enter_dir");
01326     if (mode == MODE_KMAIL)
01327         f->name = mk_kmail_dir(item->file_as); //create directory and form filename
01328     else if (mode == MODE_RECURSE)
01329         f->name = mk_recurse_dir(item->file_as);
01330     else if (mode == MODE_SEPARATE) {
01331         // do similar stuff to recurse here.
01332         mk_separate_dir(item->file_as);
01333         f->name = (char*) xmalloc(10);
01334         memset(f->name, 0, 10);
01335         //      sprintf(f->name, SEP_MAIL_FILE_TEMPLATE, f->email_count);
01336     } else {
01337         f->name = (char*) xmalloc(strlen(item->file_as)+strlen(OUTPUT_TEMPLATE)+1);
01338         sprintf(f->name, OUTPUT_TEMPLATE, item->file_as);
01339     }
01340 
01341     f->dname = (char*) xmalloc(strlen(item->file_as)+1);
01342     strcpy(f->dname, item->file_as);
01343 
01344     if (overwrite != 1) {
01345         int x = 0;
01346         char *temp = (char*) xmalloc (strlen(f->name)+10); //enough room for 10 digits
01347 
01348         sprintf(temp, "%s", f->name);
01349         check_filename(temp);
01350         while ((f->output = fopen(temp, "r"))) {
01351             DEBUG_MAIN(("need to increase filename because one already exists with that name\n"));
01352             DEBUG_MAIN(("- increasing it to %s%d\n", f->name, x));
01353             x++;
01354             sprintf(temp, "%s%08d", f->name, x);
01355             DEBUG_MAIN(("- trying \"%s\"\n", f->name));
01356             if (x == 99999999) {
01357                 DIE(("create_enter_dir: Why can I not create a folder %s? I have tried %i extensions...\n", f->name, x));
01358             }
01359             fclose(f->output);
01360         }
01361         if (x > 0) { //then the f->name should change
01362             free (f->name);
01363             f->name = temp;
01364         } else {
01365             free(temp);
01366         }
01367     }
01368 
01369     DEBUG_MAIN(("f->name = %s\nitem->folder_name = %s\n", f->name, item->file_as));
01370     if (mode != MODE_SEPARATE) {
01371         check_filename(f->name);
01372         if (!(f->output = fopen(f->name, "w"))) {
01373             DIE(("create_enter_dir: Could not open file \"%s\" for write\n", f->name));
01374         }
01375     }
01376     DEBUG_RET();
01377 }
01378 
01379 
01380 void close_enter_dir(struct file_ll *f)
01381 {
01382     DEBUG_MAIN(("main: Email Count for folder %s is %i\n", f->dname, f->email_count));
01383     if (output_mode != OUTPUT_QUIET)
01384         printf("\t\"%s\" - %i items done, skipped %i, should have been %i\n",
01385                f->dname, f->email_count, f->skip_count, f->stored_count);
01386     if (f->output) fclose(f->output);
01387     free(f->name);
01388     free(f->dname);
01389 
01390     if (mode == MODE_KMAIL)
01391         close_kmail_dir();
01392     else if (mode == MODE_RECURSE)
01393         close_recurse_dir();
01394     else if (mode == MODE_SEPARATE)
01395         close_separate_dir();
01396 }
01397 

Generated on Thu Dec 11 11:58:49 2008 for 'LibPst' by  doxygen 1.3.9.1