Mercurial > libpst
diff src/readpst.c @ 198:7c60d6d1c681
decode more recurrence mapi elements
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Tue, 12 May 2009 19:34:49 -0700 |
parents | 07ceebd115ce |
children | e3a46f66332b |
line wrap: on
line diff
--- a/src/readpst.c Wed May 06 10:37:46 2009 -0700 +++ b/src/readpst.c Tue May 12 19:34:49 2009 -0700 @@ -52,10 +52,13 @@ void find_html_charset(char *html, char *charset, size_t charsetlen); void find_rfc822_headers(char** extra_mime_headers); void write_body_part(FILE* f_output, pst_string *body, char *mime, char *charset, char *boundary, pst_file* pst); +void write_schedule_part_data(FILE* f_output, pst_item* item, const char* sender, const char* method); +void write_schedule_part(FILE* f_output, pst_item* item, const char* sender, const char* boundary); void write_normal_email(FILE* f_output, char f_name[], pst_item* item, int mode, int mode_MH, pst_file* pst, int save_rtf, char** extra_mime_headers); void write_vcard(FILE* f_output, pst_item *item, pst_item_contact* contact, char comment[]); -void write_appointment(FILE* f_output, pst_item *item, pst_item_appointment* appointment, - FILETIME* create_date, FILETIME* modify_date); +void write_journal(FILE* f_output, pst_item* item); +int file_time_compare(FILETIME* left, FILETIME* right); +void write_appointment(FILE* f_output, pst_item *item); void create_enter_dir(struct file_ll* f, pst_item *item); void close_enter_dir(struct file_ll *f); @@ -179,10 +182,10 @@ } } - } else if (item->email && (item->type == PST_TYPE_NOTE || item->type == PST_TYPE_REPORT)) { + } else if (item->email && ((item->type == PST_TYPE_NOTE) || (item->type == PST_TYPE_SCHEDULE) || (item->type == PST_TYPE_REPORT))) { if (!ff.type) ff.type = item->type; DEBUG_MAIN(("main: Processing Email\n")); - if ((ff.type != PST_TYPE_NOTE) && (ff.type != PST_TYPE_REPORT)) { + if ((ff.type != PST_TYPE_NOTE) && (ff.type != PST_TYPE_SCHEDULE) && (ff.type != PST_TYPE_REPORT)) { ff.skip_count++; DEBUG_MAIN(("main: I have an email type %"PRIi32", but the folder type %"PRIi32" isn't an email folder. Skipping it\n", item->type, ff.type)); } @@ -203,18 +206,8 @@ else { ff.item_count++; if (mode == MODE_SEPARATE) mk_separate_file(&ff); - fprintf(ff.output, "BEGIN:VJOURNAL\n"); - if (item->subject.str) { - pst_convert_utf8(item, &item->subject); - fprintf(ff.output, "SUMMARY:%s\n", pst_rfc2426_escape(item->subject.str)); - } - if (item->body.str) { - pst_convert_utf8(item, &item->body); - fprintf(ff.output, "DESCRIPTION:%s\n", pst_rfc2426_escape(item->body.str)); - } - if (item->journal->start) - fprintf(ff.output, "DTSTART;VALUE=DATE-TIME:%s\n", pst_rfc2445_datetime_format(item->journal->start)); - fprintf(ff.output, "END:VJOURNAL\n\n"); + write_journal(ff.output, item); + fprintf(ff.output, "\n"); } } else if (item->appointment && (item->type == PST_TYPE_APPOINTMENT)) { @@ -227,7 +220,8 @@ else { ff.item_count++; if (mode == MODE_SEPARATE) mk_separate_file(&ff); - write_appointment(ff.output, item, item->appointment, item->create_date, item->modify_date); + write_appointment(ff.output, item); + fprintf(ff.output, "\n"); } } else if (item->message_store) { @@ -1044,6 +1038,41 @@ } +void write_schedule_part_data(FILE* f_output, pst_item* item, const char* sender, const char* method) +{ + fprintf(f_output, "BEGIN:VCALENDAR\n"); + fprintf(f_output, "VERSION:2.0\n"); + fprintf(f_output, "PRODID:LibPST\n"); + fprintf(f_output, "METHOD:%s\n", method); + fprintf(f_output, "ORGANIZER;CN=\"%s\":MAILTO:%s\n", item->email->outlook_sender_name.str, sender); + write_appointment(f_output, item); + fprintf(f_output, "END:VCALENDAR\n"); +} + + +void write_schedule_part(FILE* f_output, pst_item* item, const char* sender, const char* boundary) +{ + const char* method = "REQUEST"; + const char* charset = "utf-8"; + char fname[20]; + if (!item->appointment) return; + + // inline appointment request + fprintf(f_output, "\n--%s\n", boundary); + fprintf(f_output, "Content-Type: %s; method=\"%s\"; charset=\"%s\"\n\n", "text/calendar", method, charset); + write_schedule_part_data(f_output, item, sender, method); + fprintf(f_output, "\n"); + + // attachment appointment request + snprintf(fname, sizeof(fname), "i%i.ics", rand()); + fprintf(f_output, "\n--%s\n", boundary); + fprintf(f_output, "Content-Type: %s; charset=\"%s\"; name=\"%s\"\n", "text/calendar", "utf-8", fname); + fprintf(f_output, "Content-Disposition: attachment; filename=\"%s\"\n\n", fname); + write_schedule_part_data(f_output, item, sender, method); + fprintf(f_output, "\n"); +} + + void write_normal_email(FILE* f_output, char f_name[], pst_item* item, int mode, int mode_MH, pst_file* pst, int save_rtf, char** extra_mime_headers) { char boundary[60]; @@ -1230,7 +1259,8 @@ } else if (item->attach || (item->email->rtf_compressed.data && save_rtf) || item->email->encrypted_body.data - || item->email->encrypted_htmlbody.data) { + || item->email->encrypted_htmlbody.data + || (item->type == PST_TYPE_SCHEDULE)) { // use multipart/mixed if we have attachments fprintf(f_output, "Content-Type: multipart/mixed;\n\tboundary=\"%s\"\n", boundary); } else { @@ -1295,6 +1325,10 @@ 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"); } + if (item->type == PST_TYPE_SCHEDULE) { + write_schedule_part(f_output, item, sender, boundary); + } + // other attachments { pst_item_attach* attach; @@ -1473,19 +1507,62 @@ } -void write_appointment(FILE* f_output, pst_item *item, pst_item_appointment* appointment, - FILETIME* create_date, FILETIME* modify_date) +void write_journal(FILE* f_output, pst_item* item) { + pst_item_journal* journal = item->journal; + + // make everything utf8 + pst_convert_utf8_null(item, &item->subject); + pst_convert_utf8_null(item, &item->body); + + fprintf(f_output, "BEGIN:VJOURNAL\n"); + fprintf(f_output, "DTSTAMP:%s\n", pst_rfc2445_datetime_format_now()); + if (item->create_date) + fprintf(f_output, "CREATED:%s\n", pst_rfc2445_datetime_format(item->create_date)); + if (item->modify_date) + fprintf(f_output, "LAST-MOD:%s\n", pst_rfc2445_datetime_format(item->modify_date)); + if (item->subject.str) + fprintf(f_output, "SUMMARY:%s\n", pst_rfc2426_escape(item->subject.str)); + if (item->body.str) + fprintf(f_output, "DESCRIPTION:%s\n", pst_rfc2426_escape(item->body.str)); + if (journal && journal->start) + fprintf(f_output, "DTSTART;VALUE=DATE-TIME:%s\n", pst_rfc2445_datetime_format(journal->start)); + fprintf(f_output, "END:VJOURNAL\n"); +} + + +/** + compare two FILETIME objects after converting to unix time_t. This + allows FILETIMEs that are beyond the range of time_t representaion to + be converted to 0, and therefore seem to be less than the right + side. The actual recurrence end values seen in pst files are very + large (outside the range of 32 bit time_t), but still finite. That is + a strange way to represent an infinite recurrence. + */ +int file_time_compare(FILETIME* left, FILETIME* right) +{ + time_t delta = pst_fileTimeToUnixTime(left) - pst_fileTimeToUnixTime(right); + if (delta < 0) return -1; + if (delta > 0) return 1; + return 0; +} + + +void write_appointment(FILE* f_output, pst_item* item) +{ + pst_item_appointment* appointment = item->appointment; + // make everything utf8 pst_convert_utf8_null(item, &item->subject); pst_convert_utf8_null(item, &item->body); pst_convert_utf8_null(item, &appointment->location); fprintf(f_output, "BEGIN:VEVENT\n"); - if (create_date) - fprintf(f_output, "CREATED:%s\n", pst_rfc2445_datetime_format(create_date)); - if (modify_date) - fprintf(f_output, "LAST-MOD:%s\n", pst_rfc2445_datetime_format(modify_date)); + fprintf(f_output, "DTSTAMP:%s\n", pst_rfc2445_datetime_format_now()); + if (item->create_date) + fprintf(f_output, "CREATED:%s\n", pst_rfc2445_datetime_format(item->create_date)); + if (item->modify_date) + fprintf(f_output, "LAST-MOD:%s\n", pst_rfc2445_datetime_format(item->modify_date)); if (item->subject.str) fprintf(f_output, "SUMMARY:%s\n", pst_rfc2426_escape(item->subject.str)); if (item->body.str) @@ -1509,6 +1586,15 @@ fprintf(f_output, "STATUS:CONFIRMED\n"); break; } + if (appointment->is_recurring) { + const char* rules[] = {"DAILY", "WEEKLY", "MONTHLY", "YEARLY"}; + pst_recurrence *rdata = pst_convert_recurrence(appointment); + fprintf(f_output, "RRULE:FREQ=%s", rules[rdata->type]); + if (rdata->count) fprintf(f_output, ";COUNT=%u", rdata->count); + if (rdata->interval) fprintf(f_output, ";INTERVAL=%u", rdata->interval); + fprintf(f_output, "\n"); + pst_free_recurrence(rdata); + } switch (appointment->label) { case PST_APP_LABEL_NONE: fprintf(f_output, "CATEGORIES:NONE\n"); @@ -1545,7 +1631,7 @@ break; } } - fprintf(f_output, "END:VEVENT\n\n"); + fprintf(f_output, "END:VEVENT\n"); } @@ -1617,7 +1703,15 @@ f->dname, f->item_count, f->skip_count, f->stored_count)); if (output_mode != OUTPUT_QUIET) printf("\t\"%s\" - %i items done, %i items skipped.\n", f->dname, f->item_count, f->skip_count); - if (f->output) fclose(f->output); + if (f->output) { + struct stat st; + fclose(f->output); + stat(f->name, &st); + if (!st.st_size) { + WARN(("removing empty output file %s ", f->name)); + remove(f->name); + } + } free(f->name); free(f->dname);