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

readpst.c

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

Generated on Sat Feb 7 10:22:05 2009 for 'LibPst' by  doxygen 1.3.9.1