12 #define OUTPUT_TEMPLATE "%s.%s" 13 #define OUTPUT_KMAIL_DIR_TEMPLATE ".%s.directory" 14 #define KMAIL_INDEX "../.%s.index" 15 #define SEP_MAIL_FILE_TEMPLATE "%i%s" 18 #define C_TIME_SIZE 500 44 char*
my_stristr(
char *haystack,
char *needle);
52 void header_get_subfield(
char *field,
const char *subfield,
char *body_subfield,
size_t size_subfield);
84 #define MODE_RECURSE 2 89 #define MODE_SEPARATE 3 93 #define OUTPUT_NORMAL 0 96 #define OUTPUT_QUIET 1 99 #define MIME_TYPE_DEFAULT "application/octet-stream" 100 #define RFC822 "message/rfc822" 103 #define CMODE_VCARD 0 107 #define DMODE_EXCLUDE 0 108 #define DMODE_INCLUDE 1 111 #define OTMODE_EMAIL 1 112 #define OTMODE_APPOINTMENT 2 113 #define OTMODE_JOURNAL 4 114 #define OTMODE_CONTACT 8 118 #define RTF_ATTACH_NAME "rtf-body.rtf" 120 #define RTF_ATTACH_TYPE "application/rtf" 148 #ifdef HAVE_SEMAPHORE_H 149 int shared_memory_id;
150 sem_t* global_children = NULL;
151 sem_t* output_mutex = NULL;
159 #ifdef HAVE_SEMAPHORE_H 160 if (global_children) {
168 pid_t ch = waitpid(child, &status, ((waitall) ? 0 : WNOHANG));
176 if (WIFSIGNALED(status)) {
177 int sig = WTERMSIG(status);
178 DEBUG_INFO((
"Process %d terminated with signal %d\n", child, sig));
193 sem_getvalue(global_children, &available);
206 #ifdef HAVE_SEMAPHORE_H 210 sem_wait(global_children);
211 pid_t child = fork();
216 else if (child == 0) {
248 for (; d_ptr; d_ptr = d_ptr->
next) {
252 DEBUG_WARN((
"ERROR item's desc record is NULL\n"));
266 if (item->subject.str) {
267 DEBUG_INFO((
"item->subject = %s\n", item->subject.str));
270 if (item->folder && item->file_as.str) {
271 DEBUG_INFO((
"Processing Folder \"%s\"\n", item->file_as.str));
274 printf(
"Processing Folder \"%s\"\n", item->file_as.str);
281 pid_t parent = getpid();
282 pid_t child =
try_fork(item->file_as.str);
288 #ifdef HAVE_SEMAPHORE_H 293 sem_post(global_children);
306 DEBUG_INFO((
"skipping contact: not in output type list\n"));
318 fprintf(ff.
output[
PST_TYPE_CONTACT],
"%s <%s>\n", item->contact->fullname.str, item->contact->address1.str);
327 DEBUG_INFO((
"skipping email: not in output type list\n"));
330 char *extra_mime_headers = NULL;
334 pid_t parent = getpid();
335 pid_t child =
try_fork(item->file_as.str);
347 #ifdef HAVE_SEMAPHORE_H 352 sem_post(global_children);
370 DEBUG_INFO((
"skipping journal entry: not in output type list\n"));
381 DEBUG_INFO((
"Processing Appointment Entry\n"));
384 DEBUG_INFO((
"skipping appointment: not in output type list\n"));
394 }
else if (item->message_store) {
397 DEBUG_WARN((
"item with message store content, type %i %s, skipping it\n", item->type, item->ascii_type));
401 DEBUG_WARN((
"Unknown item type %i (%s) name (%s)\n",
402 item->type, item->ascii_type, item->file_as.str));
412 int main(
int argc,
char*
const* argv) {
421 time_t now = time(NULL);
422 srand((
unsigned)now);
424 if (regcomp(&
meta_charset_pattern,
"<meta[^>]*content=\"[^>]*charset=([^>\";]*)[\";]", REG_ICASE | REG_EXTENDED)) {
425 printf(
"cannot compile regex pattern to find content charset in html bodies\n");
430 while ((c =
getopt(argc, argv,
"a:bC:c:Dd:emhj:kMo:qrSt:uVwL:8"))!= -1) {
440 if (*p ==
',') *p =
'\0';
585 #ifdef _SC_NPROCESSORS_ONLN 593 #ifdef HAVE_SEMAPHORE_H 595 shared_memory_id = shmget(IPC_PRIVATE,
sizeof(sem_t)*2, 0777);
596 if (shared_memory_id >= 0) {
597 global_children = (sem_t *)shmat(shared_memory_id, NULL, 0);
598 if (global_children == (sem_t *)-1) global_children = NULL;
599 if (global_children) {
600 output_mutex = &(global_children[1]);
602 sem_init(output_mutex, 1, 1);
604 shmctl(shared_memory_id, IPC_RMID, NULL);
611 if (!d_log) d_log =
"readpst.log";
612 #endif // defined DEBUG_ALL 613 #ifdef HAVE_SEMAPHORE_H 630 DIE((
"Cannot change to output dir %s: %s\n",
output_dir, strerror(x)));
637 DIE((
"Could not get root record\n"));
642 if (!(temp = strrchr(fname,
'/')))
643 if (!(temp = strrchr(fname,
'\\')))
659 DIE((
"Top of folders record not found. Cannot continue\n"));
669 #ifdef HAVE_SEMAPHORE_H 670 if (global_children) {
671 sem_destroy(global_children);
672 sem_destroy(output_mutex);
673 shmdt(global_children);
688 while (*p ==
'>') p++;
689 if (strncmp(p,
"From ", 5) == 0) fprintf(f,
">");
690 if ((n = strchr(body,
'\n'))) {
720 printf(
"Usage: %s [OPTIONS] {PST FILENAME}\n",
prog_name);
721 printf(
"OPTIONS:\n");
722 printf(
"\t-V\t- Version. Display program version\n");
723 printf(
"\t-C charset\t- character set for items with an unspecified character set\n");
724 printf(
"\t-D\t- Include deleted items in output\n");
725 printf(
"\t-L <level> \t- Set debug level; 1=debug,2=info,3=warn.\n");
726 printf(
"\t-M\t- Write emails in the MH (rfc822) format\n");
727 printf(
"\t-S\t- Separate. Write emails in the separate format\n");
728 printf(
"\t-a <attachment-extension-list>\t- Discard any attachment without an extension on the list\n");
729 printf(
"\t-b\t- Don't save RTF-Body attachments\n");
730 printf(
"\t-c[v|l]\t- Set the Contact output mode. -cv = VCard, -cl = EMail list\n");
731 printf(
"\t-d <filename> \t- Debug to file.\n");
732 printf(
"\t-e\t- As with -M, but include extensions on output files\n");
733 printf(
"\t-h\t- Help. This screen\n");
734 printf(
"\t-j <integer>\t- Number of parallel jobs to run\n");
735 printf(
"\t-k\t- KMail. Output in kmail format\n");
736 printf(
"\t-m\t- As with -e, but write .msg files also\n");
737 printf(
"\t-o <dirname>\t- Output directory to write files to. CWD is changed *after* opening pst file\n");
738 printf(
"\t-q\t- Quiet. Only print error messages\n");
739 printf(
"\t-r\t- Recursive. Output in a recursive format\n");
740 printf(
"\t-t[eajc]\t- Set the output type list. e = email, a = attachment, j = journal, c = contact\n");
741 printf(
"\t-u\t- Thunderbird mode. Write two extra .size and .type files\n");
742 printf(
"\t-w\t- Overwrite any output mbox files\n");
743 printf(
"\t-8\t- Output bodies in UTF-8, rather than original encoding, if UTF-8 version is available\n");
745 printf(
"Only one of -M -S -e -k -m -r should be specified\n");
752 printf(
"ReadPST / LibPST v%s\n",
VERSION);
753 #if BYTE_ORDER == BIG_ENDIAN 754 printf(
"Big Endian implementation being used.\n");
755 #elif BYTE_ORDER == LITTLE_ENDIAN 756 printf(
"Little Endian implementation being used.\n");
758 # error "Byte order not supported by this library" 774 if (errno != EEXIST) {
776 DIE((
"mk_kmail_dir: Cannot create directory %s: %s\n", dir, strerror(x)));
781 DIE((
"mk_kmail_dir: Cannot change to directory %s: %s\n", dir, strerror(x)));
800 DIE((
"close_kmail_dir: Cannot move up dir (..): %s\n", strerror(x)));
859 if (errno != EEXIST) {
861 DIE((
"mk_recurse_dir: Cannot create directory %s: %s\n", dir, strerror(x)));
866 DIE((
"mk_recurse_dir: Cannot change to directory %s: %s\n", dir, strerror(x)));
877 DIE((
"close_recurse_dir: Cannot go up dir (..): %s\n", strerror(x)));
885 size_t dirsize = strlen(dir) + 10;
886 char dir_name[dirsize];
892 snprintf(dir_name, dirsize,
"%s", dir);
897 DEBUG_INFO((
"about to try creating %s\n", dir_name));
899 if (errno != EEXIST) {
901 DIE((
"mk_separate_dir: Cannot create directory %s: %s\n", dir, strerror(x)));
909 if (chdir(dir_name)) {
911 DIE((
"mk_separate_dir: Cannot change to directory %s: %s\n", dir, strerror(x)));
916 #if !defined(WIN32) && !defined(__CYGWIN__) 918 struct dirent *dirent = NULL;
919 struct stat filestat;
920 if (!(sdir = opendir(
"./"))) {
921 DEBUG_WARN((
"mk_separate_dir: Cannot open dir \"%s\" for deletion of old contents\n",
"./"));
923 while ((dirent = readdir(sdir))) {
924 if (lstat(dirent->d_name, &filestat) != -1)
925 if (S_ISREG(filestat.st_mode)) {
926 if (unlink(dirent->d_name)) {
928 DIE((
"mk_separate_dir: unlink returned error on file %s: %s\n", dirent->d_name, strerror(y)));
946 DIE((
"close_separate_dir: Cannot go up dir (..): %s\n", strerror(x)));
957 DIE((
"mk_separate_file: The number of emails in this folder has become too high to handle\n"));
962 if (!(f->
output[t] = fopen(f->
name[t],
"w"))) {
963 DIE((
"mk_separate_file: Cannot open file to save email \"%s\"\n", f->
name[t]));
977 stat(f->
name[t], &st);
991 char *x=haystack, *y=needle, *z = NULL;
992 if (!haystack || !needle) {
995 while (*y !=
'\0' && *x !=
'\0') {
996 if (tolower(*y) == tolower(*x)) {
1009 if (*y !=
'\0')
return NULL;
1021 while ((t = strpbrk(t,
"/\\:"))) {
1040 if (!attach_filename)
return 1;
1041 char *e = strrchr(attach_filename,
'.');
1044 DEBUG_INFO((
"attachment extension %s\n", e));
1054 DEBUG_INFO((
"attachment acceptable returns %d\n", rc));
1071 DEBUG_INFO((
"Attachment %s Size is %#"PRIx64
", data = %#"PRIxPTR
", id %#"PRIx64
"\n", attach_filename, (uint64_t)attach->
data.
size, attach->
data.
data, attach->
i_id));
1077 DEBUG_WARN((
"Couldn't find i_id %#"PRIx64
". Cannot save attachment to file\n", attach->
i_id));
1084 if (!attach_filename) {
1087 sprintf(temp,
"%s-attach%i", f_name, attach_num);
1090 temp =
pst_malloc(strlen(f_name)+strlen(attach_filename)+15);
1094 sprintf(temp,
"%s-%s", f_name, attach_filename);
1096 sprintf(temp,
"%s-%s-%i", f_name, attach_filename, x);
1097 }
while ((fp = fopen(temp,
"r")) && ++x < 99999999);
1099 DIE((
"error finding attachment name. exhausted possibilities to %s\n", temp));
1102 DEBUG_INFO((
"Saving attachment to %s\n", temp));
1103 if (!(fp = fopen(temp,
"w"))) {
1104 DEBUG_WARN((
"write_separate_attachment: Cannot open attachment save file \"%s\"\n", temp));
1109 if (temp) free(temp);
1140 DEBUG_WARN((
"write_embedded_message: pst_parse_item was unable to parse the embedded message in attachment ID %llu", attach->
i_id));
1143 DEBUG_WARN((
"write_embedded_message: pst_parse_item returned type %d, not an email message", item->
type));
1145 fprintf(f_output,
"\n--%s\n", boundary);
1146 fprintf(f_output,
"Content-Type: %s\n\n", attach->
mimetype.
str);
1163 if (*curr ==
'\"' || *curr ==
'\\') {
1169 char *res = malloc(i + count + 1);
1170 char *curr_in = inp;
1171 char *curr_out = res;
1173 if (*curr_in ==
'\"' || *curr_in ==
'\\') {
1176 *curr_out++ = *curr_in++;
1189 const int8_t *x = (int8_t *)inp;
1191 if (*x <= 32) needs++;
1194 int n = strlen(inp) + 2*needs + 15;
1196 strcpy(buffer,
"utf-8''");
1198 const uint8_t *y = (uint8_t *)inp;
1199 uint8_t *z = (uint8_t *)buffer;
1200 z += strlen(buffer);
1203 *(z++) = (uint8_t)
'%';
1204 snprintf(z, 3,
"%2x", *y);
1220 DEBUG_INFO((
"Attachment Size is %#"PRIx64
", data = %#"PRIxPTR
", id %#"PRIx64
"\n", (uint64_t)attach->
data.
size, attach->
data.
data, attach->
i_id));
1226 DEBUG_WARN((
"Couldn't find ID pointer. Cannot save attachment to file\n"));
1232 fprintf(f_output,
"\n--%s\n", boundary);
1236 fprintf(f_output,
"Content-Type: %s\n", attach->
mimetype.
str);
1238 fprintf(f_output,
"Content-Transfer-Encoding: base64\n");
1241 fprintf(f_output,
"Content-ID: <%s>\n", attach->
content_id.
str);
1250 fprintf(f_output,
"Content-Disposition: attachment; \n filename*=%s;\n", rfc2231);
1255 fprintf(f_output,
" filename=\"%s\"\n\n", escaped);
1260 fprintf(f_output,
"Content-Disposition: attachment; filename=\"%s\"\n\n", attach->
filename1.
str);
1264 fprintf(f_output,
"Content-Disposition: inline\n\n");
1268 fprintf(f_output,
"\n\n");
1274 int n = strlen(field);
1275 if (strncasecmp(header, field, n) == 0)
return 1;
1276 if ((field[n-1] ==
' ') && (strncasecmp(header, field, n-1) == 0)) {
1277 char *crlftab =
"\r\n\t";
1278 DEBUG_INFO((
"Possible wrapped header = %s\n", header));
1279 if (strncasecmp(header+n-1, crlftab, 3) == 0)
return 1;
1296 if (
header_match(header,
"Microsoft Mail Internet Headers"))
return 1;
1301 if (
header_match(header,
"X-ASG-Debug-ID: " ))
return 1;
1302 if (
header_match(header,
"X-Barracuda-URL: " ))
return 1;
1304 if (strlen(header) > 2) {
1305 DEBUG_INFO((
"Ignore bogus headers = %s\n", header));
1316 if (
my_stristr(header, field) || (strncasecmp(header, field+1, strlen(field)-1) == 0)) {
1317 DEBUG_INFO((
"header block has %s header\n", field+1));
1329 snprintf(search,
sizeof(search),
" %s=", subfield);
1333 if (n && s && (s < n)) {
1335 s += strlen(search);
1342 f = strchr(s,
'\n');
1343 if (e && f && (f < e)) e = f;
1345 if (!e || (e > n)) e = n;
1348 snprintf(body_subfield, size_subfield,
"%s", s);
1350 DEBUG_INFO((
"body %s %s from headers\n", subfield, body_subfield));
1358 if (!t && (strncasecmp(header, field+1, strlen(field)-1) == 0)) t = header;
1367 char *e = strchr(field+1,
'\n');
1368 while (e && ((e[1] ==
' ') || (e[1] ==
'\t'))) {
1369 e = strchr(e+1,
'\n');
1381 if (t == header) e++;
1382 while (*e !=
'\0') {
1400 uint8_t *b = (uint8_t *)body;
1403 if ((*b < 32) && (*b != 9) && (*b != 10)) {
1404 DEBUG_INFO((
"found base64 byte %d\n", (
int)*b));
1418 const int index = 1;
1419 const int nmatch = index+1;
1420 regmatch_t match[nmatch];
1424 int s = match[index].rm_so;
1425 int e = match[index].rm_eo;
1427 char save = html[e];
1429 snprintf(charset, charsetlen,
"%s", html+s);
1431 DEBUG_INFO((
"charset %s from html text\n", charset));
1434 DEBUG_INFO((
"matching %d %d %d %d\n", match[0].rm_so, match[0].rm_eo, match[1].rm_so, match[1].rm_eo));
1448 char *headers = *extra_mime_headers;
1451 while ((temp = strstr(headers,
"\n\n"))) {
1457 char *n = strchr(t,
'\n');
1458 char *s = strstr(t,
": ");
1459 char *e = strchr(t,
';');
1460 if (!e || (e > n)) e = n;
1463 if (!strncasecmp(s,
RFC822, e-s)) {
1465 DEBUG_INFO((
"found 822 headers\n%s\n", headers));
1473 *extra_mime_headers = headers;
1483 size_t body_len = strlen(body->
str);
1485 if (body->
is_utf8 && (strcasecmp(
"utf-8", charset))) {
1493 DEBUG_INFO((
"Convert %s utf-8 to %s\n", mime, charset));
1496 if (rc == (
size_t)-1) {
1499 DEBUG_INFO((
"Failed to convert %s utf-8 to %s\n", mime, charset));
1504 newer->
b[newer->
dlen] =
'\0';
1506 body->
str = newer->
b;
1507 body_len = newer->
dlen;
1513 fprintf(f_output,
"\n--%s\n", boundary);
1514 fprintf(f_output,
"Content-Type: %s; charset=\"%s\"\n", mime, charset);
1515 if (base64) fprintf(f_output,
"Content-Transfer-Encoding: base64\n");
1516 fprintf(f_output,
"\n");
1522 fprintf(f_output,
"\n");
1535 fprintf(f_output,
"BEGIN:VCALENDAR\n");
1536 fprintf(f_output,
"VERSION:2.0\n");
1537 fprintf(f_output,
"PRODID:LibPST v%s\n",
VERSION);
1538 if (method) fprintf(f_output,
"METHOD:%s\n", method);
1539 fprintf(f_output,
"BEGIN:VEVENT\n");
1544 fprintf(f_output,
"ORGANIZER;CN=\"\":MAILTO:%s\n", sender);
1548 fprintf(f_output,
"END:VCALENDAR\n");
1554 const char* method =
"REQUEST";
1555 const char* charset =
"utf-8";
1560 fprintf(f_output,
"\n--%s\n", boundary);
1561 fprintf(f_output,
"Content-Type: %s; method=\"%s\"; charset=\"%s\"\n\n",
"text/calendar", method, charset);
1563 fprintf(f_output,
"\n");
1566 snprintf(fname,
sizeof(fname),
"i%i.ics", rand());
1567 fprintf(f_output,
"\n--%s\n", boundary);
1568 fprintf(f_output,
"Content-Type: %s; charset=\"%s\"; name=\"%s\"\n",
"text/calendar",
"utf-8", fname);
1569 fprintf(f_output,
"Content-Disposition: attachment; filename=\"%s\"\n\n", fname);
1571 fprintf(f_output,
"\n");
1578 char altboundary[66];
1579 char *altboundaryp = NULL;
1580 char body_charset[30];
1581 char buffer_charset[30];
1582 char body_report[60];
1584 int sender_known = 0;
1588 char *headers = NULL;
1589 int has_from, has_subject, has_to, has_cc, has_date, has_msgid;
1590 has_from = has_subject = has_to = has_cc = has_date = has_msgid = 0;
1599 strncpy(body_charset,
pst_default_charset(item,
sizeof(buffer_charset), buffer_charset),
sizeof(body_charset));
1600 body_charset[
sizeof(body_charset)-1] =
'\0';
1601 strncpy(body_report,
"delivery-status",
sizeof(body_report));
1602 body_report[
sizeof(body_report)-1] =
'\0';
1611 temp =
"MAILER-DAEMON";
1613 strncpy(sender, temp,
sizeof(sender));
1614 sender[
sizeof(sender)-1] =
'\0';
1619 c_time = ctime(&em_time);
1621 c_time[strlen(c_time)-1] =
'\0';
1623 c_time =
"Thu Jan 1 00:00:00 1970";
1625 c_time =
"Thu Jan 1 00:00:00 1970";
1628 snprintf(boundary,
sizeof(boundary),
"--boundary-LibPST-iamunique-%i_-_-", rand());
1629 snprintf(altboundary,
sizeof(altboundary),
"alt-%s", boundary);
1636 temp = strstr(headers,
"\n\n");
1643 if (!*extra_mime_headers) *extra_mime_headers = temp+2;
1644 DEBUG_INFO((
"Found extra mime headers\n%s\n", temp+2));
1661 if (!sender_known) {
1666 char *n = strchr(t,
'\n');
1667 char *s = strchr(t,
'<');
1668 char *e = strchr(t,
'>');
1669 if (s && e && n && (s < e) && (e < n)) {
1672 snprintf(sender,
sizeof(sender),
"%s", s+1);
1700 char *quo = (embedding) ?
">" :
"";
1701 fprintf(f_output,
"%sFrom \"%s\" %s\n", quo, sender, c_time);
1706 int len = strlen(headers);
1708 fprintf(f_output,
"%s", headers);
1710 if (headers[len-1] !=
'\n') fprintf(f_output,
"\n");
1728 fprintf(f_output,
"Status: RO\n");
1738 fprintf(f_output,
"From: <%s>\n", sender);
1745 fprintf(f_output,
"Subject: %s\n", item->
subject.
str);
1747 fprintf(f_output,
"Subject: \n");
1764 gmtime_r(&em_time, &stm);
1765 strftime(c_time,
C_TIME_SIZE,
"%a, %d %b %Y %H:%M:%S %z", &stm);
1766 fprintf(f_output,
"Date: %s\n", c_time);
1789 fprintf(f_output,
"MIME-Version: 1.0\n");
1792 fprintf(f_output,
"Content-Type: multipart/report; report-type=%s;\n\tboundary=\"%s\"\n", body_report, boundary);
1795 fprintf(f_output,
"Content-Type: multipart/mixed;\n\tboundary=\"%s\"\n", boundary);
1797 fprintf(f_output,
"\n");
1802 fprintf(f_output,
"\n");
1807 fprintf(f_output,
"\n--%s\n", boundary);
1808 fprintf(f_output,
"Content-Type: multipart/alternative;\n\tboundary=\"%s\"\n", altboundary);
1809 altboundaryp = altboundary;
1812 altboundaryp = boundary;
1826 fprintf(f_output,
"\n--%s--\n", altboundary);
1831 DEBUG_INFO((
"Adding RTF body as attachment\n"));
1844 DEBUG_INFO((
"Adding encrypted text body as attachment\n"));
1855 DEBUG_INFO((
"Adding encrypted HTML body as attachment\n"));
1872 for (attach = item->
attach; attach; attach = attach->
next) {
1876 DEBUG_INFO((
"Attempting Attachment encoding\n"));
1878 DEBUG_INFO((
"have an embedded rfc822 message attachment\n"));
1899 fprintf(f_output,
"\n--%s--\n\n", boundary);
1906 char* result = NULL;
1907 size_t resultlen = 0;
1908 char time_buffer[30];
1970 fprintf(f_output,
"BEGIN:VCARD\n");
1994 fprintf(f_output,
"%s;",
"");
2006 fprintf(f_output,
"%s;",
"");
2018 fprintf(f_output,
"%s;",
"");
2045 fprintf(f_output,
"AGENT:BEGIN:VCARD\n");
2050 if (comment) fprintf(f_output,
"NOTE:%s\n",
pst_rfc2426_escape(comment, &result, &resultlen));
2055 fprintf(f_output,
"VERSION:3.0\n");
2056 fprintf(f_output,
"END:VCARD\n\n");
2057 if (result) free(result);
2071 char* result = NULL;
2072 size_t resultlen = 0;
2074 const char *fmt =
"CATEGORIES:%s";
2075 int category_started = 0;
2077 if (strcmp(ef->
field_name,
"Keywords") == 0) {
2080 category_started = 1;
2084 if (category_started) fprintf(f_output,
"\n");
2085 if (result) free(result);
2086 return category_started;
2092 char* result = NULL;
2093 size_t resultlen = 0;
2094 char time_buffer[30];
2101 fprintf(f_output,
"BEGIN:VJOURNAL\n");
2111 if (journal && journal->
start)
2113 fprintf(f_output,
"END:VJOURNAL\n");
2114 if (result) free(result);
2120 char* result = NULL;
2121 size_t resultlen = 0;
2122 char time_buffer[30];
2130 fprintf(f_output,
"UID:%#"PRIx64
"\n", item->
block_id);
2140 if (appointment && appointment->
start)
2142 if (appointment && appointment->
end)
2147 switch (appointment->
showas) {
2149 fprintf(f_output,
"STATUS:TENTATIVE\n");
2153 fprintf(f_output,
"TRANSP:TRANSPARENT\n");
2156 fprintf(f_output,
"STATUS:CONFIRMED\n");
2160 const char* rules[] = {
"DAILY",
"WEEKLY",
"MONTHLY",
"YEARLY"};
2161 const char* days[] = {
"SU",
"MO",
"TU",
"WE",
"TH",
"FR",
"SA"};
2163 fprintf(f_output,
"RRULE:FREQ=%s", rules[rdata->
type]);
2164 if (rdata->
count) fprintf(f_output,
";COUNT=%u", rdata->
count);
2174 memset(byday, 0,
sizeof(byday));
2175 for (i=0; i<7; i++) {
2179 snprintf(temp,
sizeof(temp),
"%s%s%s", byday, (empty) ?
";BYDAY=" :
";", days[i]);
2180 strcpy(byday, temp);
2184 fprintf(f_output,
"%s", byday);
2186 fprintf(f_output,
"\n");
2189 switch (appointment->
label) {
2194 fprintf(f_output,
"CATEGORIES:IMPORTANT\n");
2197 fprintf(f_output,
"CATEGORIES:BUSINESS\n");
2200 fprintf(f_output,
"CATEGORIES:PERSONAL\n");
2203 fprintf(f_output,
"CATEGORIES:VACATION\n");
2206 fprintf(f_output,
"CATEGORIES:MUST-ATTEND\n");
2209 fprintf(f_output,
"CATEGORIES:TRAVEL-REQUIRED\n");
2212 fprintf(f_output,
"CATEGORIES:NEEDS-PREPARATION\n");
2215 fprintf(f_output,
"CATEGORIES:BIRTHDAY\n");
2218 fprintf(f_output,
"CATEGORIES:ANNIVERSARY\n");
2221 fprintf(f_output,
"CATEGORIES:PHONE-CALL\n");
2226 fprintf(f_output,
"BEGIN:VALARM\n");
2227 fprintf(f_output,
"TRIGGER:-PT%dM\n", appointment->
alarm_minutes);
2228 fprintf(f_output,
"ACTION:DISPLAY\n");
2229 fprintf(f_output,
"DESCRIPTION:Reminder\n");
2230 fprintf(f_output,
"END:VALARM\n");
2233 fprintf(f_output,
"END:VEVENT\n");
2234 if (result) free(result);
2240 memset(f, 0,
sizeof(*f));
2265 FILE *type_file = fopen(
".type",
"w");
2266 fprintf(type_file,
"%d\n", item->
type);
2298 sprintf(temp,
"%s", f->
name[t]);
2300 while ((f->
output[t] = fopen(temp,
"r"))) {
2301 DEBUG_INFO((
"need to increase filename because one already exists with that name\n"));
2303 sprintf(temp,
"%s%08d", f->
name[t], x);
2304 DEBUG_INFO((
"- bump file name and try \"%s\"\n", temp));
2305 if (x == 99999999) {
2306 DIE((
"create_enter_dir: Why can I not create a folder %s? I have tried %i extensions...\n", f->
name[t], x));
2318 if (!(f->
output[t] = fopen(f->
name[t],
"w"))) {
2319 DIE((
"create_enter_dir: Could not open file \"%s\" for write\n", f->
name[t]));
2332 DEBUG_INFO((
"processed item count for folder %s is %i, skipped %i, total %i \n",
2348 stat(f->
name[t], &st);
2363 FILE *type_file = fopen(
".size",
"w");
pst_string sender_address
mapi element 0x0065 PR_SENT_REPRESENTING_EMAIL_ADDRESS
char * item_type_to_name(int32_t item_type)
uint32_t bydaymask
bit mask of days of the week
int32_t alarm_minutes
mapi element 0x8501 PR_OUTLOOK_COMMON_REMINDER_MINUTES_BEFORE
void check_filename(char *fname)
#define PST_APP_LABEL_BUSINESS
pst_binary encrypted_htmlbody
mapi element 0x6f02
pst_item_appointment * appointment
calendar mapi elements
FILETIME * modify_date
mapi element 0x3008 PR_LAST_MODIFICATION_TIME
int32_t flags
mapi element 0x0e07 PR_MESSAGE_FLAGS
pst_string subject
mapi element 0x0037 PR_SUBJECT
pst_vbuf * pst_vballoc(size_t len)
char * pst_lzfu_decompress(char *rtfcomp, uint32_t compsize, size_t *size)
decompress lz compressed rtf data.
uint32_t position
occurrence of day for 2nd Tuesday of month, in which case position is 2
void header_strip_field(char *header, char *field)
int32_t reduced_item_type(int32_t item_type)
pst_string header
mapi element 0x007d PR_TRANSPORT_MESSAGE_HEADERS
struct pst_desc_tree * child_tail
void header_has_field(char *header, char *field, int *flag)
FILETIME * create_date
mapi element 0x3007 PR_CREATION_TIME
void write_body_part(FILE *f_output, pst_string *body, char *mime, char *charset, char *boundary, pst_file *pst)
pst_recurrence * pst_convert_recurrence(pst_item_appointment *appt)
Decode raw recurrence data into a better structure.
struct pst_desc_tree * parent
void pst_rfc2047(pst_item *item, pst_string *str, int needs_quote)
Convert str to rfc2047 encoding of str, possibly enclosed in quotes if it contains spaces...
void mk_separate_dir(char *dir)
int alarm
mapi element 0x8503 PR_OUTLOOK_COMMON_REMINDER_SET
void pst_freeItem(pst_item *item)
Free the item returned by pst_parse_item().
void write_msg_email(char *fname, pst_item *item, pst_file *pst)
#define PST_APP_LABEL_VACATION
int pst_load_extended_attributes(pst_file *pf)
Try to load the extended attributes from the pst file.
pst_item_journal * journal
journal mapi elements
int contact_mode_specified
char * pst_rfc2426_escape(char *str, char **buf, size_t *buflen)
Add any necessary escape characters for rfc2426 vcard format.
void * pst_malloc(size_t size)
uint64_t block_id
block id that can be used to generate uid
pst_binary encrypted_body
mapi element 0x6f04
#define PST_FREEBUSY_BUSY
int pst_close(pst_file *pf)
Close a pst file.
void write_schedule_part(FILE *f_output, pst_item *item, const char *sender, const char *boundary)
#define PST_TYPE_SCHEDULE
void write_email_body(FILE *f, char *body)
#define PST_APP_LABEL_IMPORTANT
int32_t showas
mapi element 0x8205 PR_OUTLOOK_EVENT_SHOW_TIME_AS
#define PST_APP_LABEL_ANNIVERSARY
This contains the common mapi elements, and pointers to structures for each major mapi item type...
int32_t method
mapi element 0x3705 PR_ATTACH_METHOD
int getopt(int argc, char *const *argv, char *optstring)
This contains the attachment related mapi elements.
size_t pst_attach_to_file_base64(pst_file *pf, pst_item_attach *attach, FILE *fp)
Write a binary attachment base64 encoded to a file.
const char * pst_default_charset(pst_item *item, int buflen, char *result)
Get the default character set for this item.
pst_binary data
mapi element 0x3701 PR_ATTACH_DATA_OBJ
pst_string report_text
mapi element 0x1001 PR_REPORT_TEXT, delivery report dsn body
pst_string file_as
mapi element 0x3001 PR_DISPLAY_NAME
void find_html_charset(char *html, char *charset, size_t charsetlen)
#define OTMODE_APPOINTMENT
pst_string messageid
mapi element 0x1035
#define PST_ATTACH_EMBEDDED
#define MIME_TYPE_DEFAULT
void write_journal(FILE *f_output, pst_item *item)
uint32_t monthofyear
month of year for yearly recurrences
The string is either utf8 encoded, or it is in the code page specified by the containing mapi object...
size_t pst_vb_utf8to8bit(pst_vbuf *dest, const char *inbuf, int iblen, const char *charset)
struct pst_desc_tree * next
pst_desc_tree * pst_getTopOfFolders(pst_file *pf, const pst_item *root)
Get the top of folders descriptor tree.
int acceptable_ext(pst_item_attach *attach)
check if the file name extension is acceptable.
pst_string mimetype
mapi element 0x370e PR_ATTACH_MIME_TAG
int32_t label
mapi element 0x8214
struct pst_desc_tree * child
int pst_open(pst_file *pf, const char *name, const char *charset)
Open a pst file.
void pst_vbgrow(pst_vbuf *vb, size_t len)
out: vbavail(vb) >= len, data are preserved
pst_index_ll * pst_getID(pst_file *pf, uint64_t i_id)
Lookup the i_id in the index linked list, and return a pointer to the element.
time_t pst_fileTimeToUnixTime(const FILETIME *filetime)
Convert a FILETIME to unix time_t value.
void header_get_subfield(char *field, const char *subfield, char *body_subfield, size_t size_subfield)
char * pst_rfc2445_datetime_format_now(int buflen, char *result)
Convert the current time rfc2445 date/time format 19531015T231000Z.
pst_string cc_address
mapi element 0x0e03 PR_DISPLAY_CC
char * rfc2231_string(char *inp)
Convert inp to rfc2231 encoding of string.
#define PST_FREEBUSY_TENTATIVE
void mk_recurse_dir(char *dir)
#define PST_FREEBUSY_OUT_OF_OFFICE
pst_string sentto_address
mapi element 0x0e04 PR_DISPLAY_TO
void mk_kmail_dir(char *fname)
FILETIME * sent_date
mapi element 0x0039 PR_CLIENT_SUBMIT_TIME
pst_string filename1
mapi element 0x3704 PR_ATTACH_FILENAME
uint32_t dayofmonth
day of month for monthly and yearly recurrences
pst_string body
mapi element 0x1000 PR_BODY
pst_item_message_store * message_store
message store mapi elements
int test_base64(char *body, size_t len)
FILETIME * end
mapi element 0x820e PR_OUTLOOK_EVENT_START_END
#define PST_TYPE_STICKYNOTE
#define DEBUG_HEXDUMPC(x, s, c)
uint32_t interval
recurrence interval in terms of the recurrence type
void pst_free_recurrence(pst_recurrence *r)
Free a recurrence structure.
#define PST_APP_LABEL_TRAVEL_REQ
char * pst_base64_encode(void *data, size_t size)
void create_enter_dir(struct file_ll *f, pst_item *item)
#define RET_DERROR(res, ret_val, x)
void write_appointment(FILE *f_output, pst_item *item)
uint64_t i_id
calculated from id2_val during creation of record
pst_string bcc_address
mapi element 0x0e02 PR_DISPLAY_BCC
char * my_stristr(char *haystack, char *needle)
#define PST_APP_LABEL_PHONE_CALL
pst_index_ll * assoc_tree
int write_extra_categories(FILE *f_output, pst_item *item)
write extra vcard or vcalendar categories from the extra keywords fields
char * header_get_field(char *header, char *field)
int is_recurring
mapi element 0x8223 PR_OUTLOOK_EVENT_IS_RECURRING
pst_string htmlbody
mapi element 0x1013
int type
derived from mapi elements 0x001a PR_MESSAGE_CLASS or 0x3613 PR_CONTAINER_CLASS
void write_separate_attachment(char f_name[], pst_item_attach *attach, int attach_num, pst_file *pst)
int pst_reopen(pst_file *pf)
Reopen the pst file after a fork.
char * pst_rfc2425_datetime_format(const FILETIME *ft, int buflen, char *result)
Convert a FILETIME into rfc2425 date/time format 1953-10-15T23:10:00Z which is the same as one of the...
regex_t meta_charset_pattern
void process(pst_item *outeritem, pst_desc_tree *d_ptr)
This contains the appointment related mapi elements.
pst_item_extra_field * extra_fields
linked list of extra headers and such
char * header_end_field(char *field)
int main(int argc, char *const *argv)
#define PST_APP_LABEL_MUST_ATTEND
pst_string outlook_sender_name
mapi element 0x0042 PR_SENT_REPRESENTING_NAME
pst_binary rtf_compressed
mapi element 0x1009 PR_RTF_COMPRESSED, the compressed rtf body data.
#define PST_APP_LABEL_BIRTHDAY
void close_separate_file(struct file_ll *f)
pst_item * pst_parse_item(pst_file *pf, pst_desc_tree *d_ptr, pst_id2_tree *m_head)
Process a high level object from the pst file.
pid_t try_fork(char *folder)
void close_enter_dir(struct file_ll *f)
pst_string filename2
mapi element 0x3707 PR_ATTACH_LONG_FILENAME
int pst_stricmp(char *a, char *b)
compare strings case-insensitive.
size_t pst_attach_to_file(pst_file *pf, pst_item_attach *attach, FILE *fp)
Write a binary attachment to a file.
This contains the journal related mapi elements.
void write_schedule_part_data(FILE *f_output, pst_item *item, const char *sender, const char *method)
#define OUTPUT_KMAIL_DIR_TEMPLATE
char * pst_rfc2445_datetime_format(const FILETIME *ft, int buflen, char *result)
Convert a FILETIME into rfc2445 date/time format 19531015T231000Z.
pst_desc_tree * d_head
the head and tail of the top level of the descriptor tree
void find_rfc822_headers(char **extra_mime_headers)
#define PST_APP_LABEL_NONE
void mk_separate_file(struct file_ll *f, int32_t t, char *extension, int openit)
#define PST_APP_LABEL_NEEDS_PREP
pst_item_email * email
email mapi elements
#define PST_FREEBUSY_FREE
#define PST_TYPE_APPOINTMENT
pst_item_attach * attach
linked list of attachments
void write_vcard(FILE *f_output, pst_item *item, pst_item_contact *contact, char comment[])
FILETIME * start
mapi element 0x820d PR_OUTLOOK_EVENT_START_DATE
#define DEBUG_INIT(fname, mutex)
struct pst_item_attach * next
uint32_t count
number of occurrences, even if recurrence terminates based on date
void write_embedded_message(FILE *f_output, pst_item_attach *attach, char *boundary, pst_file *pf, int save_rtf, char **extra_mime_headers)
char * acceptable_extensions
int pst_load_index(pst_file *pf)
Load the index entries from the pst file.
size_t pst_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
fwrite with checking for null pointer.
struct pst_desc_tree * prev
void write_normal_email(FILE *f_output, char f_name[], pst_item *item, int mode, int mode_MH, pst_file *pst, int save_rtf, int embedding, char **extra_mime_headers)
pst_item_folder * folder
folder mapi elements
void pst_convert_utf8_null(pst_item *item, pst_string *str)
Convert str to utf8 if possible; null strings are preserved.
int header_match(char *header, char *field)
int valid_headers(char *header)
pst_id2_tree * id2_head
id2 tree needed to resolve attachments by reference
FILETIME * start
mapi element 0x8706
#define PST_APP_LABEL_PERSONAL
char * quote_string(char *inp)
Backslash-escape quotes and backslashes in the given string.
int32_t item_count
mapi element 0x3602 PR_CONTENT_COUNT
This contains the recurrence data separated into fields.
void write_inline_attachment(FILE *f_output, pst_item_attach *attach, char *boundary, pst_file *pst)
void pst_convert_utf8(pst_item *item, pst_string *str)
Convert str to utf8 if possible; null strings are converted into empty strings.
#define SEP_MAIL_FILE_TEMPLATE
void pst_debug_setlevel(int level)
pst_string location
mapi element 0x8208 PR_OUTLOOK_EVENT_LOCATION
pst_string content_id
mapi element 0x3712 PR_ATTACH_CONTENT_ID