changeset 50:fb3818370dd6 stable-0-6-4

more fixes for 64 bit format
author carl
date Sat, 19 Jan 2008 16:30:16 -0800
parents 17654fbdf76b
children 06c0262ad689
files AUTHORS ChangeLog Doxyfile TODO regression/regression-tests.bash src/libpst.c src/libpst.h src/lspst.c src/readpst.c xml/libpst.in
diffstat 10 files changed, 377 insertions(+), 170 deletions(-) [+]
line wrap: on
line diff
--- 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.s@earthcorp.com>
-Dave Smith <davesmith@users.sourceforge.net>
+Original version by:
+    Dave Smith <dave.s@earthcorp.com>
+    Dave Smith <davesmith@users.sourceforge.net>
+
+Current maintainer:
+    Carl Byington <carl@five-ten-sg.com>
 
 With contributions by:
     Joseph Nahmias <jello@costa.debian.org> -- bounces
     Joseph Nahmias <joe@nahmias.net>
-    Carl Byington <carl@five-ten-sg.com>
     Arne Ahrend <aahrend@web.de>
     Nigel Horne <njh@bandsman.co.uk>
     Chris Halls <halls@debian.org>
--- 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)
 ===============================
--- 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.
--- 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.
 
--- 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
 
--- 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<subblocks.subblock_count; i++) {
             b_ptr += pst_decode_type3(pf, &table3_rec, b_ptr);
             subblocks.subs[i].buf       = NULL;
@@ -1397,7 +1405,7 @@
     }
     else {
         // setup the subblock descriptors, but we only have one block
-        subblocks.subblock_count = 1;
+        subblocks.subblock_count = (size_t)1;
         subblocks.subs = malloc(sizeof(pst_subblock));
         subblocks.subs[0].buf       = buf;
         subblocks.subs[0].read_size = read_size;
@@ -1551,7 +1559,7 @@
                 table_rec.type     = table2_rec.type;
                 table_rec.ref_type = table2_rec.ref_type;
                 table_rec.value    = 0;
-                if ((ind2_end - ind2_ptr) >= (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; y<count; y++) {
+        b_ptr += pst_decode_type3(pf, &table3_rec, b_ptr);
+        z = pst_ff_getIDblock_dec(pf, table3_rec.id, &buf2);
+        if (!z) {
+            DEBUG_WARN(("call to getIDblock returned zero %i\n", z));
+            if (buf2) free(buf2);
+            free(buf3);
+            return z;
+        }
+        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
             }
-            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);
--- 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;
 
 
--- 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 <string.h>
 #include <ctype.h>
 #include <errno.h>
+#include <unistd.h>
 
 #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 <filename> \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();
 }
--- 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");
--- 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 @@
 
     <refentry id="readpst.1">
         <refentryinfo>
-            <date>2008-01-15</date>
+            <date>2008-01-19</date>
         </refentryinfo>
 
         <refmeta>
@@ -212,7 +212,7 @@
 
     <refentry id="lspst.1">
         <refentryinfo>
-            <date>2008-01-15</date>
+            <date>2008-01-19</date>
         </refentryinfo>
 
         <refmeta>
@@ -230,10 +230,39 @@
             <title>Synopsis</title>
             <cmdsynopsis>
                 <command>lspst</command>
+                <arg><option>-d <replaceable class="parameter">debug-file</replaceable></option></arg>
+                <arg><option>-h</option></arg>
+                <arg><option>-V</option></arg>
                 <arg choice='plain'>pstfile</arg>
             </cmdsynopsis>
         </refsynopsisdiv>
 
+        <refsect1 id='lspst.options.1'>
+            <title>Options</title>
+            <variablelist>
+                <varlistentry>
+                    <term>-d <replaceable class="parameter">debug-file</replaceable></term>
+                    <listitem><para>
+                        Specify name of debug log file. The
+                        log file is not an ascii file, it is a binary file readable
+                        by <command>readpstlog</command>.
+                    </para></listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>-h</term>
+                    <listitem><para>
+                        Show summary of options and exit.
+                    </para></listitem>
+                </varlistentry>
+                <varlistentry>
+                    <term>-V</term>
+                    <listitem><para>
+                        Show program version and exit.
+                    </para></listitem>
+                </varlistentry>
+            </variablelist>
+        </refsect1>
+
         <refsect1 id='lspst.description.1'>
             <title>Description</title>
             <para><command>lspst</command> is a program that can read an Outlook
@@ -286,7 +315,7 @@
 
     <refentry id="readpstlog.1">
         <refentryinfo>
-            <date>2008-01-15</date>
+            <date>2008-01-19</date>
         </refentryinfo>
 
         <refmeta>
@@ -461,7 +490,7 @@
 
     <refentry id="pst2ldif.1">
         <refentryinfo>
-            <date>2008-01-15</date>
+            <date>2008-01-19</date>
         </refentryinfo>
 
         <refmeta>
@@ -585,7 +614,7 @@
 
     <refentry id="pst.5">
         <refentryinfo>
-            <date>2008-01-15</date>
+            <date>2008-01-19</date>
         </refentryinfo>
 
         <refmeta>