Mercurial > libpst
comparison 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 |
comparison
equal
deleted
inserted
replaced
197:07ceebd115ce | 198:7c60d6d1c681 |
---|---|
50 void header_strip_field(char *header, char *field); | 50 void header_strip_field(char *header, char *field); |
51 int test_base64(char *body); | 51 int test_base64(char *body); |
52 void find_html_charset(char *html, char *charset, size_t charsetlen); | 52 void find_html_charset(char *html, char *charset, size_t charsetlen); |
53 void find_rfc822_headers(char** extra_mime_headers); | 53 void find_rfc822_headers(char** extra_mime_headers); |
54 void write_body_part(FILE* f_output, pst_string *body, char *mime, char *charset, char *boundary, pst_file* pst); | 54 void write_body_part(FILE* f_output, pst_string *body, char *mime, char *charset, char *boundary, pst_file* pst); |
55 void write_schedule_part_data(FILE* f_output, pst_item* item, const char* sender, const char* method); | |
56 void write_schedule_part(FILE* f_output, pst_item* item, const char* sender, const char* boundary); | |
55 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); | 57 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); |
56 void write_vcard(FILE* f_output, pst_item *item, pst_item_contact* contact, char comment[]); | 58 void write_vcard(FILE* f_output, pst_item *item, pst_item_contact* contact, char comment[]); |
57 void write_appointment(FILE* f_output, pst_item *item, pst_item_appointment* appointment, | 59 void write_journal(FILE* f_output, pst_item* item); |
58 FILETIME* create_date, FILETIME* modify_date); | 60 int file_time_compare(FILETIME* left, FILETIME* right); |
61 void write_appointment(FILE* f_output, pst_item *item); | |
59 void create_enter_dir(struct file_ll* f, pst_item *item); | 62 void create_enter_dir(struct file_ll* f, pst_item *item); |
60 void close_enter_dir(struct file_ll *f); | 63 void close_enter_dir(struct file_ll *f); |
61 | 64 |
62 const char* prog_name; | 65 const char* prog_name; |
63 char* output_dir = "."; | 66 char* output_dir = "."; |
177 pst_convert_utf8(item, &item->contact->address1); | 180 pst_convert_utf8(item, &item->contact->address1); |
178 fprintf(ff.output, "%s <%s>\n", item->contact->fullname.str, item->contact->address1.str); | 181 fprintf(ff.output, "%s <%s>\n", item->contact->fullname.str, item->contact->address1.str); |
179 } | 182 } |
180 } | 183 } |
181 | 184 |
182 } else if (item->email && (item->type == PST_TYPE_NOTE || item->type == PST_TYPE_REPORT)) { | 185 } else if (item->email && ((item->type == PST_TYPE_NOTE) || (item->type == PST_TYPE_SCHEDULE) || (item->type == PST_TYPE_REPORT))) { |
183 if (!ff.type) ff.type = item->type; | 186 if (!ff.type) ff.type = item->type; |
184 DEBUG_MAIN(("main: Processing Email\n")); | 187 DEBUG_MAIN(("main: Processing Email\n")); |
185 if ((ff.type != PST_TYPE_NOTE) && (ff.type != PST_TYPE_REPORT)) { | 188 if ((ff.type != PST_TYPE_NOTE) && (ff.type != PST_TYPE_SCHEDULE) && (ff.type != PST_TYPE_REPORT)) { |
186 ff.skip_count++; | 189 ff.skip_count++; |
187 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)); | 190 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)); |
188 } | 191 } |
189 else { | 192 else { |
190 char *extra_mime_headers = NULL; | 193 char *extra_mime_headers = NULL; |
201 DEBUG_MAIN(("main: I have a journal entry, but the folder type %"PRIi32" isn't a journal folder. Skipping it\n", ff.type)); | 204 DEBUG_MAIN(("main: I have a journal entry, but the folder type %"PRIi32" isn't a journal folder. Skipping it\n", ff.type)); |
202 } | 205 } |
203 else { | 206 else { |
204 ff.item_count++; | 207 ff.item_count++; |
205 if (mode == MODE_SEPARATE) mk_separate_file(&ff); | 208 if (mode == MODE_SEPARATE) mk_separate_file(&ff); |
206 fprintf(ff.output, "BEGIN:VJOURNAL\n"); | 209 write_journal(ff.output, item); |
207 if (item->subject.str) { | 210 fprintf(ff.output, "\n"); |
208 pst_convert_utf8(item, &item->subject); | |
209 fprintf(ff.output, "SUMMARY:%s\n", pst_rfc2426_escape(item->subject.str)); | |
210 } | |
211 if (item->body.str) { | |
212 pst_convert_utf8(item, &item->body); | |
213 fprintf(ff.output, "DESCRIPTION:%s\n", pst_rfc2426_escape(item->body.str)); | |
214 } | |
215 if (item->journal->start) | |
216 fprintf(ff.output, "DTSTART;VALUE=DATE-TIME:%s\n", pst_rfc2445_datetime_format(item->journal->start)); | |
217 fprintf(ff.output, "END:VJOURNAL\n\n"); | |
218 } | 211 } |
219 | 212 |
220 } else if (item->appointment && (item->type == PST_TYPE_APPOINTMENT)) { | 213 } else if (item->appointment && (item->type == PST_TYPE_APPOINTMENT)) { |
221 if (!ff.type) ff.type = item->type; | 214 if (!ff.type) ff.type = item->type; |
222 DEBUG_MAIN(("main: Processing Appointment Entry\n")); | 215 DEBUG_MAIN(("main: Processing Appointment Entry\n")); |
225 DEBUG_MAIN(("main: I have an appointment, but the folder type %"PRIi32" isn't an appointment folder. Skipping it\n", ff.type)); | 218 DEBUG_MAIN(("main: I have an appointment, but the folder type %"PRIi32" isn't an appointment folder. Skipping it\n", ff.type)); |
226 } | 219 } |
227 else { | 220 else { |
228 ff.item_count++; | 221 ff.item_count++; |
229 if (mode == MODE_SEPARATE) mk_separate_file(&ff); | 222 if (mode == MODE_SEPARATE) mk_separate_file(&ff); |
230 write_appointment(ff.output, item, item->appointment, item->create_date, item->modify_date); | 223 write_appointment(ff.output, item); |
224 fprintf(ff.output, "\n"); | |
231 } | 225 } |
232 | 226 |
233 } else if (item->message_store) { | 227 } else if (item->message_store) { |
234 // there should only be one message_store, and we have already done it | 228 // there should only be one message_store, and we have already done it |
235 ff.skip_count++; | 229 ff.skip_count++; |
1042 } | 1036 } |
1043 DEBUG_RET(); | 1037 DEBUG_RET(); |
1044 } | 1038 } |
1045 | 1039 |
1046 | 1040 |
1041 void write_schedule_part_data(FILE* f_output, pst_item* item, const char* sender, const char* method) | |
1042 { | |
1043 fprintf(f_output, "BEGIN:VCALENDAR\n"); | |
1044 fprintf(f_output, "VERSION:2.0\n"); | |
1045 fprintf(f_output, "PRODID:LibPST\n"); | |
1046 fprintf(f_output, "METHOD:%s\n", method); | |
1047 fprintf(f_output, "ORGANIZER;CN=\"%s\":MAILTO:%s\n", item->email->outlook_sender_name.str, sender); | |
1048 write_appointment(f_output, item); | |
1049 fprintf(f_output, "END:VCALENDAR\n"); | |
1050 } | |
1051 | |
1052 | |
1053 void write_schedule_part(FILE* f_output, pst_item* item, const char* sender, const char* boundary) | |
1054 { | |
1055 const char* method = "REQUEST"; | |
1056 const char* charset = "utf-8"; | |
1057 char fname[20]; | |
1058 if (!item->appointment) return; | |
1059 | |
1060 // inline appointment request | |
1061 fprintf(f_output, "\n--%s\n", boundary); | |
1062 fprintf(f_output, "Content-Type: %s; method=\"%s\"; charset=\"%s\"\n\n", "text/calendar", method, charset); | |
1063 write_schedule_part_data(f_output, item, sender, method); | |
1064 fprintf(f_output, "\n"); | |
1065 | |
1066 // attachment appointment request | |
1067 snprintf(fname, sizeof(fname), "i%i.ics", rand()); | |
1068 fprintf(f_output, "\n--%s\n", boundary); | |
1069 fprintf(f_output, "Content-Type: %s; charset=\"%s\"; name=\"%s\"\n", "text/calendar", "utf-8", fname); | |
1070 fprintf(f_output, "Content-Disposition: attachment; filename=\"%s\"\n\n", fname); | |
1071 write_schedule_part_data(f_output, item, sender, method); | |
1072 fprintf(f_output, "\n"); | |
1073 } | |
1074 | |
1075 | |
1047 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) | 1076 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) |
1048 { | 1077 { |
1049 char boundary[60]; | 1078 char boundary[60]; |
1050 char body_charset[60]; | 1079 char body_charset[60]; |
1051 char body_report[60]; | 1080 char body_report[60]; |
1228 // multipart/report for DSN/MDN reports | 1257 // multipart/report for DSN/MDN reports |
1229 fprintf(f_output, "Content-Type: multipart/report; report-type=%s;\n\tboundary=\"%s\"\n", body_report, boundary); | 1258 fprintf(f_output, "Content-Type: multipart/report; report-type=%s;\n\tboundary=\"%s\"\n", body_report, boundary); |
1230 } | 1259 } |
1231 else if (item->attach || (item->email->rtf_compressed.data && save_rtf) | 1260 else if (item->attach || (item->email->rtf_compressed.data && save_rtf) |
1232 || item->email->encrypted_body.data | 1261 || item->email->encrypted_body.data |
1233 || item->email->encrypted_htmlbody.data) { | 1262 || item->email->encrypted_htmlbody.data |
1263 || (item->type == PST_TYPE_SCHEDULE)) { | |
1234 // use multipart/mixed if we have attachments | 1264 // use multipart/mixed if we have attachments |
1235 fprintf(f_output, "Content-Type: multipart/mixed;\n\tboundary=\"%s\"\n", boundary); | 1265 fprintf(f_output, "Content-Type: multipart/mixed;\n\tboundary=\"%s\"\n", boundary); |
1236 } else { | 1266 } else { |
1237 // else use multipart/alternative | 1267 // else use multipart/alternative |
1238 fprintf(f_output, "Content-Type: multipart/alternative;\n\tboundary=\"%s\"\n", boundary); | 1268 fprintf(f_output, "Content-Type: multipart/alternative;\n\tboundary=\"%s\"\n", boundary); |
1291 attach->data.data = item->email->encrypted_htmlbody.data; | 1321 attach->data.data = item->email->encrypted_htmlbody.data; |
1292 attach->data.size = item->email->encrypted_htmlbody.size; | 1322 attach->data.size = item->email->encrypted_htmlbody.size; |
1293 item->email->encrypted_htmlbody.data = NULL; | 1323 item->email->encrypted_htmlbody.data = NULL; |
1294 } | 1324 } |
1295 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"); | 1325 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"); |
1326 } | |
1327 | |
1328 if (item->type == PST_TYPE_SCHEDULE) { | |
1329 write_schedule_part(f_output, item, sender, boundary); | |
1296 } | 1330 } |
1297 | 1331 |
1298 // other attachments | 1332 // other attachments |
1299 { | 1333 { |
1300 pst_item_attach* attach; | 1334 pst_item_attach* attach; |
1471 fprintf(f_output, "END:VCARD\n\n"); | 1505 fprintf(f_output, "END:VCARD\n\n"); |
1472 DEBUG_RET(); | 1506 DEBUG_RET(); |
1473 } | 1507 } |
1474 | 1508 |
1475 | 1509 |
1476 void write_appointment(FILE* f_output, pst_item *item, pst_item_appointment* appointment, | 1510 void write_journal(FILE* f_output, pst_item* item) |
1477 FILETIME* create_date, FILETIME* modify_date) | 1511 { |
1478 { | 1512 pst_item_journal* journal = item->journal; |
1513 | |
1514 // make everything utf8 | |
1515 pst_convert_utf8_null(item, &item->subject); | |
1516 pst_convert_utf8_null(item, &item->body); | |
1517 | |
1518 fprintf(f_output, "BEGIN:VJOURNAL\n"); | |
1519 fprintf(f_output, "DTSTAMP:%s\n", pst_rfc2445_datetime_format_now()); | |
1520 if (item->create_date) | |
1521 fprintf(f_output, "CREATED:%s\n", pst_rfc2445_datetime_format(item->create_date)); | |
1522 if (item->modify_date) | |
1523 fprintf(f_output, "LAST-MOD:%s\n", pst_rfc2445_datetime_format(item->modify_date)); | |
1524 if (item->subject.str) | |
1525 fprintf(f_output, "SUMMARY:%s\n", pst_rfc2426_escape(item->subject.str)); | |
1526 if (item->body.str) | |
1527 fprintf(f_output, "DESCRIPTION:%s\n", pst_rfc2426_escape(item->body.str)); | |
1528 if (journal && journal->start) | |
1529 fprintf(f_output, "DTSTART;VALUE=DATE-TIME:%s\n", pst_rfc2445_datetime_format(journal->start)); | |
1530 fprintf(f_output, "END:VJOURNAL\n"); | |
1531 } | |
1532 | |
1533 | |
1534 /** | |
1535 compare two FILETIME objects after converting to unix time_t. This | |
1536 allows FILETIMEs that are beyond the range of time_t representaion to | |
1537 be converted to 0, and therefore seem to be less than the right | |
1538 side. The actual recurrence end values seen in pst files are very | |
1539 large (outside the range of 32 bit time_t), but still finite. That is | |
1540 a strange way to represent an infinite recurrence. | |
1541 */ | |
1542 int file_time_compare(FILETIME* left, FILETIME* right) | |
1543 { | |
1544 time_t delta = pst_fileTimeToUnixTime(left) - pst_fileTimeToUnixTime(right); | |
1545 if (delta < 0) return -1; | |
1546 if (delta > 0) return 1; | |
1547 return 0; | |
1548 } | |
1549 | |
1550 | |
1551 void write_appointment(FILE* f_output, pst_item* item) | |
1552 { | |
1553 pst_item_appointment* appointment = item->appointment; | |
1554 | |
1479 // make everything utf8 | 1555 // make everything utf8 |
1480 pst_convert_utf8_null(item, &item->subject); | 1556 pst_convert_utf8_null(item, &item->subject); |
1481 pst_convert_utf8_null(item, &item->body); | 1557 pst_convert_utf8_null(item, &item->body); |
1482 pst_convert_utf8_null(item, &appointment->location); | 1558 pst_convert_utf8_null(item, &appointment->location); |
1483 | 1559 |
1484 fprintf(f_output, "BEGIN:VEVENT\n"); | 1560 fprintf(f_output, "BEGIN:VEVENT\n"); |
1485 if (create_date) | 1561 fprintf(f_output, "DTSTAMP:%s\n", pst_rfc2445_datetime_format_now()); |
1486 fprintf(f_output, "CREATED:%s\n", pst_rfc2445_datetime_format(create_date)); | 1562 if (item->create_date) |
1487 if (modify_date) | 1563 fprintf(f_output, "CREATED:%s\n", pst_rfc2445_datetime_format(item->create_date)); |
1488 fprintf(f_output, "LAST-MOD:%s\n", pst_rfc2445_datetime_format(modify_date)); | 1564 if (item->modify_date) |
1565 fprintf(f_output, "LAST-MOD:%s\n", pst_rfc2445_datetime_format(item->modify_date)); | |
1489 if (item->subject.str) | 1566 if (item->subject.str) |
1490 fprintf(f_output, "SUMMARY:%s\n", pst_rfc2426_escape(item->subject.str)); | 1567 fprintf(f_output, "SUMMARY:%s\n", pst_rfc2426_escape(item->subject.str)); |
1491 if (item->body.str) | 1568 if (item->body.str) |
1492 fprintf(f_output, "DESCRIPTION:%s\n", pst_rfc2426_escape(item->body.str)); | 1569 fprintf(f_output, "DESCRIPTION:%s\n", pst_rfc2426_escape(item->body.str)); |
1493 if (appointment && appointment->start) | 1570 if (appointment && appointment->start) |
1506 fprintf(f_output, "TRANSP:TRANSPARENT\n"); | 1583 fprintf(f_output, "TRANSP:TRANSPARENT\n"); |
1507 case PST_FREEBUSY_BUSY: | 1584 case PST_FREEBUSY_BUSY: |
1508 case PST_FREEBUSY_OUT_OF_OFFICE: | 1585 case PST_FREEBUSY_OUT_OF_OFFICE: |
1509 fprintf(f_output, "STATUS:CONFIRMED\n"); | 1586 fprintf(f_output, "STATUS:CONFIRMED\n"); |
1510 break; | 1587 break; |
1588 } | |
1589 if (appointment->is_recurring) { | |
1590 const char* rules[] = {"DAILY", "WEEKLY", "MONTHLY", "YEARLY"}; | |
1591 pst_recurrence *rdata = pst_convert_recurrence(appointment); | |
1592 fprintf(f_output, "RRULE:FREQ=%s", rules[rdata->type]); | |
1593 if (rdata->count) fprintf(f_output, ";COUNT=%u", rdata->count); | |
1594 if (rdata->interval) fprintf(f_output, ";INTERVAL=%u", rdata->interval); | |
1595 fprintf(f_output, "\n"); | |
1596 pst_free_recurrence(rdata); | |
1511 } | 1597 } |
1512 switch (appointment->label) { | 1598 switch (appointment->label) { |
1513 case PST_APP_LABEL_NONE: | 1599 case PST_APP_LABEL_NONE: |
1514 fprintf(f_output, "CATEGORIES:NONE\n"); | 1600 fprintf(f_output, "CATEGORIES:NONE\n"); |
1515 break; | 1601 break; |
1543 case PST_APP_LABEL_PHONE_CALL: | 1629 case PST_APP_LABEL_PHONE_CALL: |
1544 fprintf(f_output, "CATEGORIES:PHONE-CALL\n"); | 1630 fprintf(f_output, "CATEGORIES:PHONE-CALL\n"); |
1545 break; | 1631 break; |
1546 } | 1632 } |
1547 } | 1633 } |
1548 fprintf(f_output, "END:VEVENT\n\n"); | 1634 fprintf(f_output, "END:VEVENT\n"); |
1549 } | 1635 } |
1550 | 1636 |
1551 | 1637 |
1552 void create_enter_dir(struct file_ll* f, pst_item *item) | 1638 void create_enter_dir(struct file_ll* f, pst_item *item) |
1553 { | 1639 { |
1615 { | 1701 { |
1616 DEBUG_MAIN(("main: processed item count for folder %s is %i, skipped %i, total %i \n", | 1702 DEBUG_MAIN(("main: processed item count for folder %s is %i, skipped %i, total %i \n", |
1617 f->dname, f->item_count, f->skip_count, f->stored_count)); | 1703 f->dname, f->item_count, f->skip_count, f->stored_count)); |
1618 if (output_mode != OUTPUT_QUIET) printf("\t\"%s\" - %i items done, %i items skipped.\n", | 1704 if (output_mode != OUTPUT_QUIET) printf("\t\"%s\" - %i items done, %i items skipped.\n", |
1619 f->dname, f->item_count, f->skip_count); | 1705 f->dname, f->item_count, f->skip_count); |
1620 if (f->output) fclose(f->output); | 1706 if (f->output) { |
1707 struct stat st; | |
1708 fclose(f->output); | |
1709 stat(f->name, &st); | |
1710 if (!st.st_size) { | |
1711 WARN(("removing empty output file %s ", f->name)); | |
1712 remove(f->name); | |
1713 } | |
1714 } | |
1621 free(f->name); | 1715 free(f->name); |
1622 free(f->dname); | 1716 free(f->dname); |
1623 | 1717 |
1624 if (mode == MODE_KMAIL) | 1718 if (mode == MODE_KMAIL) |
1625 close_kmail_dir(); | 1719 close_kmail_dir(); |