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();