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

Generated on Tue Aug 5 12:06:14 2008 for 'LibPst' by  doxygen 1.3.9.1