# HG changeset patch # User carl # Date 1200789016 28800 # Node ID fb3818370dd6755faa8632167cd3ea149a0e53dd # Parent 17654fbdf76be572e9bf05bb4fadd4ffe6cb1600 more fixes for 64 bit format diff -r 17654fbdf76b -r fb3818370dd6 AUTHORS --- a/AUTHORS Sat Jan 19 10:47:16 2008 -0800 +++ b/AUTHORS Sat Jan 19 16:30:16 2008 -0800 @@ -1,10 +1,13 @@ -Dave Smith -Dave Smith +Original version by: + Dave Smith + Dave Smith + +Current maintainer: + Carl Byington With contributions by: Joseph Nahmias -- bounces Joseph Nahmias - Carl Byington Arne Ahrend Nigel Horne Chris Halls diff -r 17654fbdf76b -r fb3818370dd6 ChangeLog --- a/ChangeLog Sat Jan 19 10:47:16 2008 -0800 +++ b/ChangeLog Sat Jan 19 16:30:16 2008 -0800 @@ -6,6 +6,19 @@ * Document type 0x0101 descriptor blocks and process them. * Fix large file support - we need to include config.h before any standard headers. + * Merge following changes from svn snapshot from Alioth: + * Add new fields to appointment for recurring events + (SourceForge #304198) + * Map IPM.Task items to PST_TYPE_TASK. + * Applied patch to remove compiler warnings, thanks! + (SourceForge #304314) + * Fix crash with unknown reference type + * Fix more memory issues detected by valgrind + * lspst - add usage mesage and option parsing using getopt + (SourceForge #304199) + * Fix crash caused by invalid free calls + * Fix crash when email subject is empty + * Fix memory and information leak in hex debug dump LibPST 0.6.3 (2008-01-13) =============================== diff -r 17654fbdf76b -r fb3818370dd6 Doxyfile --- a/Doxyfile Sat Jan 19 10:47:16 2008 -0800 +++ b/Doxyfile Sat Jan 19 16:30:16 2008 -0800 @@ -186,7 +186,7 @@ # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. -OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_FOR_C = YES # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources # only. Doxygen will then generate output that is more tailored for Java. diff -r 17654fbdf76b -r fb3818370dd6 TODO --- a/TODO Sat Jan 19 10:47:16 2008 -0800 +++ b/TODO Sat Jan 19 16:30:16 2008 -0800 @@ -2,6 +2,6 @@ 1) case 0x360A: // PR_SUBFOLDERS Has children -Is that really an int32_t flag. All the other boolean flags seem be +Is that really an int32_t flag? All the other boolean flags seem be int16_t. diff -r 17654fbdf76b -r fb3818370dd6 regression/regression-tests.bash --- a/regression/regression-tests.bash Sat Jan 19 10:47:16 2008 -0800 +++ b/regression/regression-tests.bash Sat Jan 19 16:30:16 2008 -0800 @@ -26,8 +26,8 @@ $val ../src/readpst -cv -o output8 -d dumper big_mail.pst >out8.err 2>&1 ../src/readpstlog -f I dumper >big_mail.log -$val ../src/lspst ams.pst >out8.err 2>&1 - ../src/readpstlog -f I lspst.debug >lspst.log +$val ../src/lspst -d dumper ams.pst >out9.err 2>&1 + ../src/readpstlog -f I dumper >ams.log rm -f dumper lspst.debug diff -r 17654fbdf76b -r fb3818370dd6 src/libpst.c --- a/src/libpst.c Sat Jan 19 10:47:16 2008 -0800 +++ b/src/libpst.c Sat Jan 19 16:30:16 2008 -0800 @@ -64,23 +64,28 @@ uint32_t u1; uint32_t offset; }; + + struct pst_table_ptr_structn{ uint64_t start; uint64_t u1; uint64_t offset; }; + typedef struct pst_block_header { uint16_t type; uint16_t count; } pst_block_header; + typedef struct pst_id2_assoc32 { uint32_t id2; uint32_t id; uint32_t table2; } pst_id2_assoc32; + typedef struct pst_id2_assoc { uint32_t id2; // only 32 bit here? uint16_t unknown1; @@ -89,15 +94,24 @@ uint64_t table2; } pst_id2_assoc; + typedef struct pst_table3_rec32 { uint32_t id; } pst_table3_rec32; //for type 3 (0x0101) blocks + typedef struct pst_table3_rec { uint64_t id; } pst_table3_rec; //for type 3 (0x0101) blocks +typedef struct pst_block_hdr { + uint16_t index_offset; + uint16_t type; + uint32_t offset; +} pst_block_hdr; + + // this is an array of the un-encrypted values. the un-encrypted value is in the position // of the encrypted value. ie the encrypted value 0x13 represents 0x02 // 0 1 2 3 4 5 6 7 @@ -1306,12 +1320,8 @@ unsigned char* ind2_end = NULL; unsigned char* ind2_ptr = NULL; pst_x_attrib_ll *mapptr; - - struct { - uint16_t index_offset; - uint16_t type; - uint32_t offset; - } block_hdr; + pst_block_hdr block_hdr; + pst_table3_rec table3_rec; //for type 3 (0x0101) blocks struct { unsigned char seven_c; @@ -1345,8 +1355,6 @@ uint8_t slot; } table2_rec; //for type 2 (0x7CEC) blocks - pst_table3_rec table3_rec; //for type 3 (0x0101) blocks - DEBUG_ENT("pst_parse_block"); if ((read_size = pst_ff_getIDblock_dec(pf, block_id, &buf)) == 0) { WARN(("Error reading block id %#llx\n", block_id)); @@ -1370,10 +1378,10 @@ DEBUG_EMAIL(("block header (index_offset=%#hx, type=%#hx, offset=%#hx)\n", block_hdr.index_offset, block_hdr.type, block_hdr.offset)); if (block_hdr.index_offset == (uint16_t)0x0101) { //type 3 + size_t i; + char *b_ptr = buf + 8; subblocks.subblock_count = block_hdr.type; subblocks.subs = malloc(sizeof(pst_subblock) * subblocks.subblock_count); - size_t i; - char *b_ptr = buf + 8; for (i=0; i= (table2_rec.ind2_off + table2_rec.size)) { + if ((ind2_end - ind2_ptr) >= (int)(table2_rec.ind2_off + table2_rec.size)) { size_t n = table2_rec.size; size_t m = sizeof(table_rec.value); if (n <= m) { @@ -1671,7 +1679,7 @@ } } else { - value_size = block_offset7.to - block_offset7.from; + value_size = (size_t)(block_offset7.to - block_offset7.from); na_ptr->items[x]->size = value_size; na_ptr->items[x]->type = table_rec.ref_type; na_ptr->items[x]->data = xmalloc(value_size+1); @@ -1863,6 +1871,8 @@ item->type = PST_TYPE_JOURNAL; else if (pst_strincmp("IPM.Appointment", item->ascii_type, 15) == 0) item->type = PST_TYPE_APPOINTMENT; + else if (pst_strincmp("IPM.Task", item->ascii_type, 8) == 0) + item->type = PST_TYPE_TASK; else item->type = PST_TYPE_OTHER; @@ -2245,7 +2255,9 @@ DEBUG_EMAIL(("Attachment Size - ")); NULL_CHECK(attach); MOVE_NEXT(attach); - memcpy(&(attach->size), list->items[x]->data, sizeof(attach->size)); + t = (*(int32_t*)list->items[x]->data); + LE32_CPU(t); + attach->size = (size_t)t; DEBUG_EMAIL(("%i\n", attach->size)); break; case 0x0FF9: // PR_RECORD_KEY Record Header 1 @@ -3205,6 +3217,18 @@ LIST_COPY(item->appointment->location, (char*)); DEBUG_EMAIL(("%s\n", item->appointment->location)); break; + case 0x820d: // Appointment start + DEBUG_EMAIL(("Appointment Date Start - ")); + MALLOC_APPOINTMENT(item); + LIST_COPY(item->appointment->start, (FILETIME*)); + DEBUG_EMAIL(("%s\n", fileTimeToAscii(item->appointment->start))); + break; + case 0x820e: // Appointment end + DEBUG_EMAIL(("Appointment Date End - ")); + MALLOC_APPOINTMENT(item); + LIST_COPY(item->appointment->end, (FILETIME*)); + DEBUG_EMAIL(("%s\n", fileTimeToAscii(item->appointment->end))); + break; case 0x8214: // Label for an appointment DEBUG_EMAIL(("Label for appointment - ")); MALLOC_APPOINTMENT(item); @@ -3246,32 +3270,84 @@ item->appointment->all_day = 0; } break; + case 0x8231: // Recurrence type + // 1: Daily + // 2: Weekly + // 3: Monthly + // 4: Yearly + DEBUG_EMAIL(("Appointment reccurs - ")); + MALLOC_APPOINTMENT(item); + memcpy(&(item->appointment->recurrence_type), list->items[x]->data, sizeof(item->appointment->recurrence_type)); + LE32_CPU(item->appointment->recurrence_type); + switch (item->appointment->recurrence_type) { + case PST_APP_RECUR_DAILY: + DEBUG_EMAIL(("Daily\n")); break; + case PST_APP_RECUR_WEEKLY: + DEBUG_EMAIL(("Weekly\n")); break; + case PST_APP_RECUR_MONTHLY: + DEBUG_EMAIL(("Monthly\n")); break; + case PST_APP_RECUR_YEARLY: + DEBUG_EMAIL(("Yearly\n")); break; + default: + DEBUG_EMAIL(("Unknown Value: %d\n", item->appointment->recurrence_type)); break; + } + break; + case 0x8232: // Recurrence description + DEBUG_EMAIL(("Appointment recurrence description - ")); + MALLOC_APPOINTMENT(item); + LIST_COPY(item->appointment->recurrence, (char*)); + DEBUG_EMAIL(("%s\n", item->appointment->recurrence)); + break; case 0x8234: // TimeZone as String DEBUG_EMAIL(("TimeZone of times - ")); MALLOC_APPOINTMENT(item); LIST_COPY(item->appointment->timezonestring, (char*)); DEBUG_EMAIL(("%s\n", item->appointment->timezonestring)); break; - case 0x8235: // Appointment start time - DEBUG_EMAIL(("Appointment Start Time - ")); + case 0x8235: // Recurrence start date + DEBUG_EMAIL(("Recurrence Start Date - ")); + MALLOC_APPOINTMENT(item); + LIST_COPY(item->appointment->recurrence_start, (FILETIME*)); + DEBUG_EMAIL(("%s\n", fileTimeToAscii(item->appointment->recurrence_start))); + break; + case 0x8236: // Recurrence end date + DEBUG_EMAIL(("Recurrence End Date - ")); MALLOC_APPOINTMENT(item); - LIST_COPY(item->appointment->start, (FILETIME*)); - DEBUG_EMAIL(("%s\n", fileTimeToAscii((FILETIME*)item->appointment->start))); - break; - case 0x8236: // Appointment end time - DEBUG_EMAIL(("Appointment End Time - ")); + LIST_COPY(item->appointment->recurrence_end, (FILETIME*)); + DEBUG_EMAIL(("%s\n", fileTimeToAscii(item->appointment->recurrence_end))); + break; + case 0x8501: // Reminder minutes before appointment start + DEBUG_EMAIL(("Alarm minutes - ")); + MALLOC_APPOINTMENT(item); + memcpy(&(item->appointment->alarm_minutes), list->items[x]->data, sizeof(item->appointment->alarm_minutes)); + LE32_CPU(item->appointment->alarm_minutes); + DEBUG_EMAIL(("%i\n", item->appointment->alarm_minutes)); + break; + case 0x8503: // Reminder alarm + DEBUG_EMAIL(("Reminder alarm - ")); MALLOC_APPOINTMENT(item); - LIST_COPY(item->appointment->end, (FILETIME*)); - DEBUG_EMAIL(("%s\n", fileTimeToAscii((FILETIME*)item->appointment->start))); - break; - case 0x8516: // Journal time start - DEBUG_EMAIL(("Duplicate Time Start - ")); + if (*(int16_t*)list->items[x]->data != 0) { + DEBUG_EMAIL(("True\n")); + item->appointment->alarm = 1; + } else { + DEBUG_EMAIL(("False\n")); + item->appointment->alarm = 0; + } + break; + case 0x8516: + DEBUG_EMAIL(("Appointment Start Date 3 - ")); DEBUG_EMAIL(("%s\n", fileTimeToAscii((FILETIME*)list->items[x]->data))); break; - case 0x8517: // Journal time end - DEBUG_EMAIL(("Duplicate Time End - ")); + case 0x8517: + DEBUG_EMAIL(("Appointment End Date 3 - ")); DEBUG_EMAIL(("%s\n", fileTimeToAscii((FILETIME*)list->items[x]->data))); break; + case 0x851f: // Play reminder sound filename + DEBUG_EMAIL(("Appointment reminder sound filename - ")); + MALLOC_APPOINTMENT(item); + LIST_COPY(item->appointment->alarm_filename, (char*)); + DEBUG_EMAIL(("%s\n", item->appointment->alarm_filename)); + break; case 0x8530: // Followup DEBUG_EMAIL(("Followup String - ")); MALLOC_CONTACT(item); @@ -3726,9 +3802,13 @@ if (item->appointment) { SAFE_FREE(item->appointment->location); SAFE_FREE(item->appointment->reminder); + SAFE_FREE(item->appointment->alarm_filename); SAFE_FREE(item->appointment->start); SAFE_FREE(item->appointment->end); SAFE_FREE(item->appointment->timezonestring); + SAFE_FREE(item->appointment->recurrence); + SAFE_FREE(item->appointment->recurrence_start); + SAFE_FREE(item->appointment->recurrence_end); free(item->appointment); } SAFE_FREE(item->ascii_type); @@ -3771,6 +3851,10 @@ p->needfree = 1; } else { + if (p->from) { + DEBUG_WARN(("size zero but non-null pointer\n")); + free(p->from); + } p->from = p->to = NULL; } } @@ -4123,6 +4207,14 @@ } +/** + * Get an ID block from file using _pst_ff_getIDblock and decrypt if necessary + * @param pf PST file structure + * @param id ID of block to retrieve + * @param b Reference to pointer that will be set to new block. Any memory + pointed to by buffer will be free()d beforehand + * @return Size of block pointed to by *b + */ size_t pst_ff_getIDblock_dec(pst_file *pf, uint64_t id, unsigned char **b) { size_t r; int noenc = (int)(id & 2); // disable encryption @@ -4138,6 +4230,14 @@ } +/** + * Read a block of data from file into memory + * @param pf PST file + * @param id identifier of block to read + * @param b reference to pointer to buffer. If this pointer + is non-NULL, it will first be free()d + * @return size of block read into memory + */ size_t pst_ff_getIDblock(pst_file *pf, uint64_t id, unsigned char** b) { pst_index_ll *rec; size_t rsize = 0; @@ -4173,6 +4273,7 @@ #define PST_PTR_BLOCK_SIZE 0x120 size_t pst_ff_getID2block(pst_file *pf, uint64_t id2, pst_index2_ll *id2_head, unsigned char** buf) { + size_t ret; pst_index_ll* ptr; pst_holder h = {buf, NULL, 0, "", 0}; DEBUG_ENT("pst_ff_getID2block"); @@ -4183,8 +4284,9 @@ DEBUG_RET(); return 0; } + ret = pst_ff_getID2data(pf, ptr, &h); DEBUG_RET(); - return pst_ff_getID2data(pf, ptr, &h); + return ret; } @@ -4228,6 +4330,9 @@ uint32_t x, b; unsigned char * buf3 = NULL, *buf2 = NULL, *t; unsigned char fdepth; + unsigned char *b_ptr; + pst_block_hdr block_hdr; + pst_table3_rec table3_rec; //for type 3 (0x0101) blocks DEBUG_ENT("pst_ff_compile_ID"); a = pst_ff_getIDblock(pf, id, &buf3); @@ -4235,10 +4340,15 @@ if (buf3) free(buf3); return 0; } - if ((buf3[0] != 0x1)) { // if bit 8 is set) { - // if ((buf3)[0] != 0x1 && (buf3)[1] > 4) { - DEBUG_WARN(("WARNING: buffer doesn't start with 0x1, but I expected it to or doesn't have it's two-bit set!\n")); - DEBUG_WARN(("Treating as normal buffer\n")); + DEBUG_HEXDUMPC(buf3, a, 0x10); + memcpy(&block_hdr, buf3, sizeof(block_hdr)); + LE16_CPU(block_hdr.index_offset); + LE16_CPU(block_hdr.type); + LE32_CPU(block_hdr.offset); + DEBUG_EMAIL(("block header (index_offset=%#hx, type=%#hx, offset=%#x)\n", block_hdr.index_offset, block_hdr.type, block_hdr.offset)); + + if (block_hdr.index_offset != (uint16_t)0x0101) { //type 3 + DEBUG_WARN(("WARNING: not a type 0x0101 buffer, Treating as normal buffer\n")); if (pf->encryption) (void)pst_decrypt(buf3, a, pf->encryption); if (h->buf) *(h->buf) = buf3; @@ -4258,64 +4368,45 @@ DEBUG_RET(); return a; } - memcpy (&count, &(buf3[2]), sizeof(int16_t)); - LE16_CPU(count); - memcpy (&fdepth, &(buf3[1]), sizeof(char)); - DEBUG_READ(("Seen index to blocks. Depth is %i\n", fdepth)); - DEBUG_READ(("There are %i ids here\n", count)); - - y = 0; - while (y < count) { - memcpy(&x, &buf3[0x08+(y*4)], sizeof(int32_t)); - LE32_CPU(x); - if (fdepth == 0x1) { - if ((z = pst_ff_getIDblock(pf, x, &buf2)) == 0) { - DEBUG_WARN(("call to getIDblock returned zero %i\n", z)); - if (buf2) free(buf2); - free(buf3); - return z; + count = block_hdr.type; + b_ptr = buf3 + 8; + for (y=0; ybuf) { + *(h->buf) = realloc(*(h->buf), size+z+1); + DEBUG_READ(("appending read data of size %i onto main buffer from pos %i\n", z, size)); + memcpy(&((*(h->buf))[size]), buf2, z); + } else if ((h->base64 == 1) && h->fp) { + // include any byte left over from the last one encoding + buf2 = (char*)realloc(buf2, z+h->base64_extra); + memmove(buf2+h->base64_extra, buf2, z); + memcpy(buf2, h->base64_extra_chars, h->base64_extra); + z += h->base64_extra; + + b = z % 3; // find out how many bytes will be left over after the encoding. + // and save them + memcpy(h->base64_extra_chars, &(buf2[z-b]), b); + h->base64_extra = b; + t = base64_encode(buf2, z-b); + if (t) { + DEBUG_READ(("writing %i bytes to file as base64 [%i]. Currently %i\n", z, strlen(t), size)); + (void)pst_fwrite(t, (size_t)1, strlen(t), h->fp); + free(t); // caught by valgrind } - if (pf->encryption) (void)pst_decrypt(buf2, z, pf->encryption); - if (h->buf) { - *(h->buf) = realloc(*(h->buf), size+z+1); - DEBUG_READ(("appending read data of size %i onto main buffer from pos %i\n", z, size)); - memcpy(&((*(h->buf))[size]), buf2, z); - } else if ((h->base64 == 1) && h->fp) { - // include any byte left over from the last one encoding - buf2 = (char*)realloc(buf2, z+h->base64_extra); - memmove(buf2+h->base64_extra, buf2, z); - memcpy(buf2, h->base64_extra_chars, h->base64_extra); - z += h->base64_extra; - - b = z % 3; // find out how many bytes will be left over after the encoding. - // and save them - memcpy(h->base64_extra_chars, &(buf2[z-b]), b); - h->base64_extra = b; - t = base64_encode(buf2, z-b); - if (t) { - DEBUG_READ(("writing %i bytes to file as base64 [%i]. Currently %i\n", z, strlen(t), size)); - (void)pst_fwrite(t, (size_t)1, strlen(t), h->fp); - free(t); // caught by valgrind - } - } else if (h->fp) { - DEBUG_READ(("writing %i bytes to file. Currently %i\n", z, size)); - (void)pst_fwrite(buf2, (size_t)1, z, h->fp); - } else { - // h-> does not specify any output - } - size += z; - y++; + } else if (h->fp) { + DEBUG_READ(("writing %i bytes to file. Currently %i\n", z, size)); + (void)pst_fwrite(buf2, (size_t)1, z, h->fp); + } else { + // h-> does not specify any output } - else { - if ((z = pst_ff_compile_ID(pf, x, h, size)) == 0) { - DEBUG_WARN(("recursive called returned zero %i\n", z)); - free(buf3); - DEBUG_RET(); - return z; - } - size = z; - y++; - } + size += z; } free(buf3); if (buf2) free(buf2); diff -r 17654fbdf76b -r fb3818370dd6 src/libpst.h --- a/src/libpst.h Sat Jan 19 10:47:16 2008 -0800 +++ b/src/libpst.h Sat Jan 19 16:30:16 2008 -0800 @@ -111,6 +111,13 @@ #define PST_APP_LABEL_ANNIVERSARY 9 // Anniversary #define PST_APP_LABEL_PHONE_CALL 10// Phone Call +// define type of reccuring event +#define PST_APP_RECUR_NONE 0 +#define PST_APP_RECUR_DAILY 1 +#define PST_APP_RECUR_WEEKLY 2 +#define PST_APP_RECUR_MONTHLY 3 +#define PST_APP_RECUR_YEARLY 4 + typedef struct pst_misc_6_struct { int32_t i1; @@ -219,9 +226,9 @@ int delete_after_submit; // 1 = true, 0 = false int delivery_report; // 1 = true, 0 = false char *encrypted_body; - int32_t encrypted_body_size; + size_t encrypted_body_size; char *encrypted_htmlbody; - int32_t encrypted_htmlbody_size; + size_t encrypted_htmlbody_size; int32_t flag; char *header; char *htmlbody; @@ -413,13 +420,20 @@ typedef struct pst_item_appointment { FILETIME *end; - char *location; + char *location; + int alarm; // 1 = true, 0 = false FILETIME *reminder; + int32_t alarm_minutes; + char *alarm_filename; FILETIME *start; - char *timezonestring; - int32_t showas; - int32_t label; - int all_day; // 1 = true, 0 = false + char *timezonestring; + int32_t showas; + int32_t label; + int all_day; // 1 = true, 0 = false + char *recurrence; + int32_t recurrence_type; + FILETIME *recurrence_start; + FILETIME *recurrence_end; } pst_item_appointment; diff -r 17654fbdf76b -r fb3818370dd6 src/lspst.c --- a/src/lspst.c Sat Jan 19 10:47:16 2008 -0800 +++ b/src/lspst.c Sat Jan 19 16:30:16 2008 -0800 @@ -14,6 +14,7 @@ #include #include #include +#include #include "libpst.h" #include "timeconv.h" @@ -29,6 +30,8 @@ void canonicalize_filename(char *fname); void debug_print(char *fmt, ...); +int usage(char *prog_name); +int version(); // global settings pst_file pstfile; @@ -88,7 +91,7 @@ DEBUG_MAIN(("main: I have a contact, but the folder isn't a contacts folder. Processing anyway\n")); } printf("Contact"); - if (item->contact->fullname != NULL) + if (item->contact->fullname) printf("\t%s", pst_rfc2426_escape(item->contact->fullname)); printf("\n"); @@ -98,9 +101,9 @@ DEBUG_MAIN(("main: I have an email, but the folder isn't an email folder. Processing anyway\n")); } printf("Email"); - if (item->email->outlook_sender_name != NULL) + if (item->email->outlook_sender_name) printf("\tFrom: %s", item->email->outlook_sender_name); - if (item->email->subject->subj != NULL) + if (item->email->subject && item->email->subject->subj) printf("\tSubject: %s", item->email->subject->subj); printf("\n"); @@ -109,7 +112,8 @@ if (ff.type != PST_TYPE_JOURNAL) { DEBUG_MAIN(("main: I have a journal entry, but folder isn't specified as a journal type. Processing...\n")); } - printf("Journal\t%s\n", pst_rfc2426_escape(item->email->subject->subj)); + if (item->email && item->email->subject && item->email->subject->subj) + printf("Journal\t%s\n", pst_rfc2426_escape(item->email->subject->subj)); } else if (item->appointment && (item->type == PST_TYPE_APPOINTMENT)) { // Process Calendar Appointment item @@ -118,15 +122,13 @@ DEBUG_MAIN(("main: I have an appointment, but folder isn't specified as an appointment type. Processing...\n")); } printf("Appointment"); - if (item->email != NULL && item->email->subject != NULL) + if (item->email && item->email->subject) printf("\tSUMMARY: %s", pst_rfc2426_escape(item->email->subject->subj)); - if (item->appointment != NULL) { - if (item->appointment->start != NULL) - printf("\tSTART: %s", pst_rfc2445_datetime_format(item->appointment->start)); - if (item->appointment->end != NULL) - printf("\tEND: %s", pst_rfc2445_datetime_format(item->appointment->end)); - printf("\tALL DAY: %s", (item->appointment->all_day==1 ? "Yes" : "No")); - } + if (item->appointment->start) + printf("\tSTART: %s", pst_rfc2445_datetime_format(item->appointment->start)); + if (item->appointment->end) + printf("\tEND: %s", pst_rfc2445_datetime_format(item->appointment->end)); + printf("\tALL DAY: %s", (item->appointment->all_day==1 ? "Yes" : "No")); printf("\n"); } else { @@ -146,13 +148,63 @@ } +int usage(char *prog_name) { + DEBUG_ENT("usage"); + version(); + printf("Usage: %s [OPTIONS] {PST FILENAME}\n", prog_name); + printf("OPTIONS:\n"); + printf("\t-d \t- Debug to file. This is a binary log. Use readlog to print it\n"); + printf("\t-h\t- Help. This screen\n"); + printf("\t-V\t- Version. Display program version\n"); + DEBUG_RET(); + return 0; +} + + +int version() { + DEBUG_ENT("version"); + printf("lspst / LibPST v%s\n", VERSION); +#if BYTE_ORDER == BIG_ENDIAN + printf("Big Endian implementation being used.\n"); +#elif BYTE_ORDER == LITTLE_ENDIAN + printf("Little Endian implementation being used.\n"); +#else +# error "Byte order not supported by this library" +#endif +#ifdef __GNUC__ + printf("GCC %d.%d : %s %s\n", __GNUC__, __GNUC_MINOR__, __DATE__, __TIME__); +#endif + DEBUG_RET(); + return 0; +} + + int main(int argc, char** argv) { pst_item *item = NULL; pst_desc_ll *d_ptr; char *temp = NULL; //temporary char pointer + int c; char *d_log = NULL; - if (argc <= 1) DIE(("Missing PST filename.\n")); + while ((c = getopt(argc, argv, "d:hV"))!= -1) { + switch (c) { + case 'd': + d_log = optarg; + break; + case 'h': + usage(argv[0]); + exit(0); + break; + case 'V': + version(); + exit(0); + break; + default: + usage(argv[0]); + exit(1); + break; + } + } #ifdef DEBUG_ALL // force a log file @@ -162,8 +214,13 @@ DEBUG_REGISTER_CLOSE(); DEBUG_ENT("main"); + if (argc <= optind) { + usage(argv[0]); + exit(2); + } + // Open PST file - if (pst_open(&pstfile, argv[1], "r")) DIE(("Error opening File\n")); + if (pst_open(&pstfile, argv[optind], "r")) DIE(("Error opening File\n")); // Load PST index if (pst_load_index(&pstfile)) DIE(("Index Error\n")); @@ -212,7 +269,7 @@ DEBUG_RET(); return; } - while ((fname = strpbrk(fname, "/\\:")) != NULL) + while (fname = strpbrk(fname, "/\\:")) *fname = '_'; DEBUG_RET(); } diff -r 17654fbdf76b -r fb3818370dd6 src/readpst.c --- a/src/readpst.c Sat Jan 19 10:47:16 2008 -0800 +++ b/src/readpst.c Sat Jan 19 16:30:16 2008 -0800 @@ -204,9 +204,9 @@ DEBUG_MAIN(("main: I have a journal entry, but the folder isn't a journal folder. Processing anyway\n")); } fprintf(ff.output, "BEGIN:VJOURNAL\n"); - if (item->email->subject) + if (item->email && item->email->subject && item->email->subject->subj) fprintf(ff.output, "SUMMARY:%s\n", pst_rfc2426_escape(item->email->subject->subj)); - if (item->email->body) + if (item->email && item->email->body) fprintf(ff.output, "DESCRIPTION:%s\n", pst_rfc2426_escape(item->email->body)); if (item->journal->start) fprintf(ff.output, "DTSTART;VALUE=DATE-TIME:%s\n", pst_rfc2445_datetime_format(item->journal->start)); @@ -459,7 +459,7 @@ int version() { DEBUG_ENT("version"); - printf("ReadPST v%s\n", VERSION); + printf("ReadPST / LibPST v%s\n", VERSION); #if BYTE_ORDER == BIG_ENDIAN printf("Big Endian implementation being used.\n"); #elif BYTE_ORDER == LITTLE_ENDIAN @@ -1097,7 +1097,7 @@ // I had tried to place those into a single printf - Carl. DEBUG_ENT("write_vcard"); - // the specification I am following is (hopefully) PST_RFC2426 vCard Mime Directory Profile + // the specification I am following is (hopefully) RFC2426 vCard Mime Directory Profile fprintf(f_output, "BEGIN:VCARD\n"); fprintf(f_output, "FN:%s\n", pst_rfc2426_escape(contact->fullname)); @@ -1213,51 +1213,51 @@ pst_rfc2426_escape(appointment->location)); if (appointment) { switch (appointment->showas) { - case PST_FREEBUSY_TENTATIVE: - fprintf(f_output, "STATUS:TENTATIVE\n"); - break; - case PST_FREEBUSY_FREE: - // mark as transparent and as confirmed - fprintf(f_output, "TRANSP:TRANSPARENT\n"); - case PST_FREEBUSY_BUSY: - case PST_FREEBUSY_OUT_OF_OFFICE: - fprintf(f_output, "STATUS:CONFIRMED\n"); - break; + case PST_FREEBUSY_TENTATIVE: + fprintf(f_output, "STATUS:TENTATIVE\n"); + break; + case PST_FREEBUSY_FREE: + // mark as transparent and as confirmed + fprintf(f_output, "TRANSP:TRANSPARENT\n"); + case PST_FREEBUSY_BUSY: + case PST_FREEBUSY_OUT_OF_OFFICE: + fprintf(f_output, "STATUS:CONFIRMED\n"); + break; } switch (appointment->label) { - case PST_APP_LABEL_NONE: - fprintf(f_output, "CATEGORIES:NONE\n"); - break; - case PST_APP_LABEL_IMPORTANT: - fprintf(f_output, "CATEGORIES:IMPORTANT\n"); - break; - case PST_APP_LABEL_BUSINESS: - fprintf(f_output, "CATEGORIES:BUSINESS\n"); - break; - case PST_APP_LABEL_PERSONAL: - fprintf(f_output, "CATEGORIES:PERSONAL\n"); - break; - case PST_APP_LABEL_VACATION: - fprintf(f_output, "CATEGORIES:VACATION\n"); - break; - case PST_APP_LABEL_MUST_ATTEND: - fprintf(f_output, "CATEGORIES:MUST-ATTEND\n"); - break; - case PST_APP_LABEL_TRAVEL_REQ: - fprintf(f_output, "CATEGORIES:TRAVEL-REQUIRED\n"); - break; - case PST_APP_LABEL_NEEDS_PREP: - fprintf(f_output, "CATEGORIES:NEEDS-PREPARATION\n"); - break; - case PST_APP_LABEL_BIRTHDAY: - fprintf(f_output, "CATEGORIES:BIRTHDAY\n"); - break; - case PST_APP_LABEL_ANNIVERSARY: - fprintf(f_output, "CATEGORIES:ANNIVERSARY\n"); - break; - case PST_APP_LABEL_PHONE_CALL: - fprintf(f_output, "CATEGORIES:PHONE-CALL\n"); - break; + case PST_APP_LABEL_NONE: + fprintf(f_output, "CATEGORIES:NONE\n"); + break; + case PST_APP_LABEL_IMPORTANT: + fprintf(f_output, "CATEGORIES:IMPORTANT\n"); + break; + case PST_APP_LABEL_BUSINESS: + fprintf(f_output, "CATEGORIES:BUSINESS\n"); + break; + case PST_APP_LABEL_PERSONAL: + fprintf(f_output, "CATEGORIES:PERSONAL\n"); + break; + case PST_APP_LABEL_VACATION: + fprintf(f_output, "CATEGORIES:VACATION\n"); + break; + case PST_APP_LABEL_MUST_ATTEND: + fprintf(f_output, "CATEGORIES:MUST-ATTEND\n"); + break; + case PST_APP_LABEL_TRAVEL_REQ: + fprintf(f_output, "CATEGORIES:TRAVEL-REQUIRED\n"); + break; + case PST_APP_LABEL_NEEDS_PREP: + fprintf(f_output, "CATEGORIES:NEEDS-PREPARATION\n"); + break; + case PST_APP_LABEL_BIRTHDAY: + fprintf(f_output, "CATEGORIES:BIRTHDAY\n"); + break; + case PST_APP_LABEL_ANNIVERSARY: + fprintf(f_output, "CATEGORIES:ANNIVERSARY\n"); + break; + case PST_APP_LABEL_PHONE_CALL: + fprintf(f_output, "CATEGORIES:PHONE-CALL\n"); + break; } } fprintf(f_output, "END:VEVENT\n\n"); diff -r 17654fbdf76b -r fb3818370dd6 xml/libpst.in --- a/xml/libpst.in Sat Jan 19 10:47:16 2008 -0800 +++ b/xml/libpst.in Sat Jan 19 16:30:16 2008 -0800 @@ -19,7 +19,7 @@ - 2008-01-15 + 2008-01-19 @@ -212,7 +212,7 @@ - 2008-01-15 + 2008-01-19 @@ -230,10 +230,39 @@ Synopsis lspst + + + pstfile + + Options + + + -d debug-file + + Specify name of debug log file. The + log file is not an ascii file, it is a binary file readable + by readpstlog. + + + + -h + + Show summary of options and exit. + + + + -V + + Show program version and exit. + + + + + Description lspst is a program that can read an Outlook @@ -286,7 +315,7 @@ - 2008-01-15 + 2008-01-19 @@ -461,7 +490,7 @@ - 2008-01-15 + 2008-01-19 @@ -585,7 +614,7 @@ - 2008-01-15 + 2008-01-19