changeset 191:4b498fd68464

add pst_attach_to_mem() back into the shared library interface. improve developer documentation. fix memory leak caught by valgrind.
author Carl Byington <carl@five-ten-sg.com>
date Wed, 15 Apr 2009 18:39:42 -0700
parents e3a63888cdd4
children 774b2e77eb50
files ChangeLog NEWS configure.in libpst.spec.in regression/regression-tests.bash src/libpst.c src/libpst.h src/readpst.c xml/libpst.in
diffstat 9 files changed, 265 insertions(+), 86 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Tue Apr 14 22:26:17 2009 -0700
+++ b/ChangeLog	Wed Apr 15 18:39:42 2009 -0700
@@ -1,3 +1,9 @@
+LibPST 0.6.37 (2009-04-15)
+===============================
+    * add pst_attach_to_mem() back into the shared library interface.
+    * improve developer documentation.
+    * fix memory leak caught by valgrind.
+
 LibPST 0.6.36 (2009-04-14)
 ===============================
     * spec file cleanup with multiple sub packages.
--- a/NEWS	Tue Apr 14 22:26:17 2009 -0700
+++ b/NEWS	Wed Apr 15 18:39:42 2009 -0700
@@ -1,3 +1,4 @@
+0.6.37  2009-04-15 add pst_attach_to_mem() back into the shared library interface.
 0.6.36  2009-04-14 build separate -doc and -devel-doc subpackages
 0.6.35  2009-04-08 properly add trailing mime boundary in all modes, build separate rpms with libpst.so shared.
 0.6.34  2009-03-19 avoid putting mixed item types into the same output folder
--- a/configure.in	Tue Apr 14 22:26:17 2009 -0700
+++ b/configure.in	Wed Apr 15 18:39:42 2009 -0700
@@ -1,5 +1,5 @@
 AC_PREREQ(2.59)
-AC_INIT(libpst,0.6.36,carl@five-ten-sg.com)
+AC_INIT(libpst,0.6.37,carl@five-ten-sg.com)
 AC_CONFIG_SRCDIR([src/libpst.c])
 AC_CONFIG_HEADER([config.h])
 AM_INIT_AUTOMAKE
@@ -19,7 +19,7 @@
 #  6. libtool will build libpst.so.x.y.z where the SONAME is libpst.so.x
 #     and x=current-age, y=age, z=revision
 
-libpst_version_info='2:0:0'
+libpst_version_info='3:0:1'
 AC_SUBST(LIBPST_VERSION_INFO, [$libpst_version_info])
 libpst_so_major='2'
 AC_SUBST(LIBPST_SO_MAJOR, [$libpst_so_major])
@@ -27,7 +27,7 @@
 # libpst
 # version    soname         so library name
 # 0.6.35     libpst.so.2    libpst.so.2.0.0
-
+# 0.6.37     libpst.so.2    libpst.so.2.1.0
 
 
 
--- a/libpst.spec.in	Tue Apr 14 22:26:17 2009 -0700
+++ b/libpst.spec.in	Wed Apr 15 18:39:42 2009 -0700
@@ -125,6 +125,10 @@
 
 
 %changelog
+* Wed Apr 15 2009 Carl Byington <carl@five-ten-sg.com> - 0.6.37-1
+- add pst_attach_to_mem() back into the shared library interface.
+- fix memory leak caught by valgrind.
+
 * Tue Apr 14 2009 Carl Byington <carl@five-ten-sg.com> - 0.6.36-1
 - build separate -doc and -devel-doc subpackages.
 - other spec file cleanup
--- a/regression/regression-tests.bash	Tue Apr 14 22:26:17 2009 -0700
+++ b/regression/regression-tests.bash	Wed Apr 15 18:39:42 2009 -0700
@@ -65,7 +65,7 @@
 
 
 val="valgrind --leak-check=full"
-val=''
+#val=''
 
 pushd ..
 make || exit
--- a/src/libpst.c	Tue Apr 14 22:26:17 2009 -0700
+++ b/src/libpst.c	Wed Apr 15 18:39:42 2009 -0700
@@ -17,7 +17,6 @@
     #pragma pack(1)
 #endif
 
-
 #define ASSERT(x) { if(!(x)) raise( SIGSEGV ); }
 
 #define INDEX_TYPE32            0x0E
@@ -448,7 +447,7 @@
     }
     else if (node->parent_d_id == node->d_id) {
         // add top level node to the descriptor tree
-        DEBUG_INDEX(("%#"PRIx64" is its own parent. What is this world coming to?\n"));
+        DEBUG_INDEX(("%#"PRIx64" is its own parent. What is this world coming to?\n", node->d_id));
         add_descriptor_to_list(node, &pf->d_head, &pf->d_tail);
     } else {
         //DEBUG_INDEX(("Searching for parent %#"PRIx64" of %#"PRIx64"\n", node->parent_d_id, node->d_id));
@@ -520,6 +519,28 @@
 }
 
 
+size_t pst_attach_to_mem(pst_file *pf, pst_item_attach *attach, char **b) {
+    pst_index_ll *ptr;
+    pst_holder h = {b, NULL, 0};
+    size_t size = 0;
+    DEBUG_ENT("pst_attach_to_mem");
+    if (attach->i_id != (uint64_t)-1) {
+        ptr = pst_getID(pf, attach->i_id);
+        if (ptr) {
+            size = pst_ff_getID2data(pf, ptr, &h);
+        } else {
+            DEBUG_WARN(("Couldn't find ID pointer. Cannot handle attachment\n"));
+        }
+        attach->data.size = size;
+    } else {
+        size = attach->data.size;
+        *b   = attach->data.data;
+    }
+    DEBUG_RET();
+    return size;
+}
+
+
 size_t pst_attach_to_file(pst_file *pf, pst_item_attach *attach, FILE* fp) {
     pst_index_ll *ptr;
     pst_holder h = {NULL, fp, 0};
@@ -558,12 +579,12 @@
         attach->data.size = size;
     } else {
         // encode the attachment to the file
-        char *c = pst_base64_encode(attach->data.data, attach->data.size);
+        size = attach->data.size;
+        char *c = pst_base64_encode(attach->data.data, size);
         if (c) {
             (void)pst_fwrite(c, (size_t)1, strlen(c), fp);
             free(c);    // caught by valgrind
         }
-        size = attach->data.size;
     }
     DEBUG_RET();
     return size;
@@ -686,7 +707,6 @@
         xattrib.map     = PST_LE_GET_UINT16(buffer+bptr), bptr += 2;
         ptr = (pst_x_attrib_ll*) pst_malloc(sizeof(*ptr));
         memset(ptr, 0, sizeof(*ptr));
-        ptr->type = xattrib.type;
         ptr->map  = xattrib.map+0x8000;
         ptr->next = NULL;
         DEBUG_INDEX(("xattrib: ext = %#"PRIx32", type = %#"PRIx16", map = %#"PRIx16"\n",
@@ -1262,20 +1282,18 @@
         pst_free_list(list);
 
         // now we will have initial information of each attachment stored in item->attach...
-        // we must now read the secondary record for each based on the id2 val associated with
+        // we must now read the secondary record for each based on the id2_val associated with
         // each attachment
-        attach = item->attach;
-        while (attach) {
+        for (attach = item->attach; attach; attach = attach->next) {
             DEBUG_WARN(("initial attachment id2 %#"PRIx64"\n", attach->id2_val));
             if ((id2_ptr = pst_getID2(id2_head, attach->id2_val))) {
                 DEBUG_WARN(("initial attachment id2 found id %#"PRIx64"\n", id2_ptr->id->i_id));
-                // id_ptr is a record describing the attachment
+                // id2_ptr is a record describing the attachment
                 // we pass NULL instead of id2_head cause we don't want it to
                 // load all the extra stuff here.
                 list = pst_parse_block(pf, id2_ptr->id->i_id, NULL);
                 if (!list) {
                     DEBUG_WARN(("ERROR error processing an attachment record\n"));
-                    attach = attach->next;
                     continue;
                 }
                 if (list->count_objects > 1) {
@@ -1284,7 +1302,6 @@
                 if (pst_process(list, item, attach)) {
                     DEBUG_WARN(("ERROR pst_process() failed with an attachment\n"));
                     pst_free_list(list);
-                    attach = attach->next;
                     continue;
                 }
                 pst_free_list(list);
@@ -1302,7 +1319,6 @@
                 DEBUG_WARN(("ERROR cannot locate id2 value %#"PRIx64"\n", attach->id2_val));
                 attach->id2_val = 0;    // suppress this missing attachment
             }
-            attach = attach->next;
         }
     }
 
@@ -2080,10 +2096,10 @@
                     if (list->elements[x]->extra) {
                         pst_item_extra_field *ef = (pst_item_extra_field*) pst_malloc(sizeof(pst_item_extra_field));
                         memset(ef, 0, sizeof(pst_item_extra_field));
-                        ef->field_name = strdup(list->elements[x]->extra);
                         LIST_COPY_CSTR(ef->value);
                         if (ef->value) {
-                            ef->next = item->extra_fields;
+                            ef->field_name = strdup(list->elements[x]->extra);
+                            ef->next       = item->extra_fields;
                             item->extra_fields = ef;
                             DEBUG_EMAIL(("Extra Field - \"%s\" = \"%s\"\n", ef->field_name, ef->value));
                             if (strcmp(ef->field_name, "content-type") == 0) {
@@ -2106,6 +2122,7 @@
                         else {
                             DEBUG_EMAIL(("What does this mean? Internet header %s value\n", list->elements[x]->extra));
                             DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
+                            free(ef);   // caught by valgrind
                         }
                     }
                     break;
@@ -3808,8 +3825,7 @@
 
 
 /**
- * Get an ID block from file using _pst_ff_getIDblock and decrypt if necessary
- *
+ * Get an ID block from file using pst_ff_getIDblock() and decrypt if necessary
  * @param pf   PST file structure
  * @param i_id ID of block to retrieve
  * @param buf  reference to pointer to buffer that will contain the data block.
@@ -4085,52 +4101,48 @@
     char *ret, *a, *b;
     size_t x = 0;
     int y, z;
+    if (!str) return NULL;
     DEBUG_ENT("rfc2426_escape");
-    if (!str)
+    // calculate space required to escape all the following characters
+    y = pst_chr_count(str, ',')
+      + pst_chr_count(str, '\\')
+      + pst_chr_count(str, ';')
+      + pst_chr_count(str, '\n');
+    z = pst_chr_count(str, '\r');
+    if (y == 0 && z == 0)
+        // there isn't any extra space required
         ret = str;
     else {
-
-        // calculate space required to escape all the following characters
-        y = pst_chr_count(str, ',')
-          + pst_chr_count(str, '\\')
-          + pst_chr_count(str, ';')
-          + pst_chr_count(str, '\n');
-        z = pst_chr_count(str, '\r');
-        if (y == 0 && z == 0)
-            // there isn't any extra space required
-            ret = str;
-        else {
-            x = strlen(str) + y - z + 1; // don't forget room for the NUL
-            if (x > buflen) {
-                buf = (char*) realloc(buf, x);
-                buflen = x;
+        x = strlen(str) + y - z + 1; // don't forget room for the NUL
+        if (x > buflen) {
+            buf = (char*) realloc(buf, x);
+            buflen = x;
+        }
+        a = str;
+        b = buf;
+        while (*a != '\0') {
+            switch (*a) {
+            case ',' :
+            case '\\':
+            case ';' :
+                *(b++) = '\\';
+                *b = *a;
+                break;
+            case '\n':  // newlines are encoded as "\n"
+                *(b++) = '\\';
+                *b = 'n';
+                break;
+            case '\r':  // skip cr
+                b--;
+                break;
+            default:
+                *b=*a;
             }
-            a = str;
-            b = buf;
-            while (*a != '\0') {
-                switch (*a) {
-                case ',' :
-                case '\\':
-                case ';' :
-                    *(b++) = '\\';
-                    *b = *a;
-                    break;
-                case '\n':  // newlines are encoded as "\n"
-                    *(b++) = '\\';
-                    *b = 'n';
-                    break;
-                case '\r':  // skip cr
-                    b--;
-                    break;
-                default:
-                    *b=*a;
-                }
-                b++;
-                a++;
-            }
-            *b = '\0'; // NUL-terminate the string (buf)
-            ret = buf;
+            b++;
+            a++;
         }
+        *b = '\0'; // NUL-terminate the string (buf)
+        ret = buf;
     }
     DEBUG_RET();
     return ret;
--- a/src/libpst.h	Tue Apr 14 22:26:17 2009 -0700
+++ b/src/libpst.h	Wed Apr 15 18:39:42 2009 -0700
@@ -681,7 +681,9 @@
 } pst_item_appointment;
 
 
-/** This contains the common mapi elements, and pointers to structures for each major mapi item type */
+/** This contains the common mapi elements, and pointers to structures for
+ *  each major mapi item type. It represents a complete mapi object.
+ */
 typedef struct pst_item {
     /** email mapi elements */
     pst_item_email         *email;
@@ -760,12 +762,26 @@
 } pst_item;
 
 
-/** linked list of extended attributes */
+/** Linked list of extended attributes.
+ *  This is used to convert mapi_id values in the pst file into
+ *  cannonical mapi_id values to be used in this code. This list
+ *  is kept in sorted order, where the key is the 'map' field.
+ *  Some mapi_id values are converted to cannonical mapi_id values
+ *  (PST_MAP_ATTRIB), and others are converted to a string
+ *  (PST_ATTRIB_HEADER).
+ */
 typedef struct pst_x_attrib_ll {
+    /** obsolete field, this is now unused */
     uint32_t type;
+    /** @li 1 PST_MAP_ATTRIB map->int attribute
+        @li 2 PST_MAP_HEADER map->string header
+     */
     uint32_t mytype;
+    /** key for the mapping */
     uint32_t map;
-    void *data;
+    /** data target of the mapping, either uint32_t or string */
+    void     *data;
+    /** link to next item in the list */
     struct pst_x_attrib_ll *next;
 } pst_x_attrib_ll;
 
@@ -819,30 +835,171 @@
 } pst_file;
 
 
+/** Open a pst file.
+ * @param pf   pointer to uninitialized pst_file structure. This structure
+ *             will be filled in by this function.
+ * @param name name of the file, suitable for fopen().
+ * @return 0 if ok, -1 if error
+ */
 int            pst_open(pst_file *pf, char *name);
-int            pst_close(pst_file *pf);
-pst_desc_tree* pst_getTopOfFolders(pst_file *pf, pst_item *root);
-size_t         pst_attach_to_file(pst_file *pf, pst_item_attach *attach, FILE* fp);
-size_t         pst_attach_to_file_base64(pst_file *pf, pst_item_attach *attach, FILE* fp);
+
+
+/** Load the index entries from the pst file. This loads both the
+ *  i_id linked list, and the d_id tree, and should normally be the
+ *  first call after pst_open().
+ * @param pf pointer to the pst_file structure setup by pst_open().
+ */
 int            pst_load_index (pst_file *pf);
-pst_desc_tree* pst_getNextDptr(pst_desc_tree* d);
+
+
+/** Load the extended attribute mapping table from the pst file. This
+ *  should normally be the second call after pst_open().
+ * @param pf pointer to the pst_file structure setup by pst_open().
+ */
 int            pst_load_extended_attributes(pst_file *pf);
-pst_item*      pst_getItem(pst_file *pf, pst_desc_tree *d_ptr);
+
+
+/** Close a pst file.
+ * @param pf pointer to the pst_file structure setup by pst_open().
+ */
+int            pst_close(pst_file *pf);
+
+
+/** Get the top of folders descriptor tree. This is the main descriptor tree
+ *  that needs to be walked to look at every item in the pst file.
+ * @param pf   pointer to the pst_file structure setup by pst_open().
+ * @param root root item, which can be obtained by pst_parse_item(pf, pf->d.head, NULL).
+ */
+pst_desc_tree* pst_getTopOfFolders(pst_file *pf, pst_item *root);
+
+
+/** Assemble the binary attachment into a single buffer.
+ * @param pf     pointer to the pst_file structure setup by pst_open().
+ * @param attach pointer to the attachment record
+ * @param b      pointer to location to store the buffer pointer. The
+ *               caller must free this buffer.
+ * @return       size of the buffer, and return the buffer pointer in *b
+ */
+size_t         pst_attach_to_mem(pst_file *pf, pst_item_attach *attach, char **b);
+
+
+/** Write a binary attachment to a file.
+ * @param pf     pointer to the pst_file structure setup by pst_open().
+ * @param attach pointer to the attachment record
+ * @param fp     pointer to an open FILE.
+ */
+size_t         pst_attach_to_file(pst_file *pf, pst_item_attach *attach, FILE* fp);
+
+
+/** Write a binary attachment base64 encoded to a file.
+ * @param pf     pointer to the pst_file structure setup by pst_open().
+ * @param attach pointer to the attachment record
+ * @param fp     pointer to an open FILE.
+ */
+size_t         pst_attach_to_file_base64(pst_file *pf, pst_item_attach *attach, FILE* fp);
+
+
+/** Walk the descriptor tree.
+ * @param d pointer to the current item in the descriptor tree.
+ * @return  pointer to the next item in the descriptor tree.
+ */
+pst_desc_tree* pst_getNextDptr(pst_desc_tree* d);
+
+
+/** Assemble a mapi object from a descriptor pointer.
+ * @param pf     pointer to the pst_file structure setup by pst_open().
+ * @param d_ptr  pointer to an item in the descriptor tree.
+ * @param m_head normally NULL. This is only used when processing embedded
+ *               attached rfc822 messages, in which case it is attach->id2_head.
+ * @return pointer to the mapi object. Must be free'd by pst_freeItem().
+ */
 pst_item*      pst_parse_item (pst_file *pf, pst_desc_tree *d_ptr, pst_id2_tree *m_head);
+
+
+/** Free the item returned by pst_parse_item().
+ * @param item  pointer to item returned from pst_parse_item().
+ */
 void           pst_freeItem(pst_item *item);
+
+
+/** Lookup the i_id in the index linked list, and return a pointer to the element.
+ * @param pf     pointer to the pst_file structure setup by pst_open().
+ * @param i_id   key for the index linked list
+ * @return pointer to the element, or NULL if not found.
+ */
 pst_index_ll*  pst_getID(pst_file* pf, uint64_t i_id);
-int            pst_decrypt(uint64_t id, char *buf, size_t size, unsigned char type);
-size_t         pst_ff_getIDblock_dec(pst_file *pf, uint64_t id, char **b);
-size_t         pst_ff_getIDblock(pst_file *pf, uint64_t id, char** b);
-size_t         pst_fwrite(const void*ptr, size_t size, size_t nmemb, FILE*stream);
+
+
+/** Decrypt a block of data from the pst file.
+ * @param i_id identifier of this block, needed as part of the key for the enigma cipher
+ * @param buf  pointer to the buffer to be decrypted
+ * @param size size of the buffer
+ * @param type
+    @li 0 PST_NO_ENCRYPT, none
+    @li 1 PST_COMP_ENCRYPT, simple byte substitution cipher with fixed key
+    @li 2 PST_ENCRYPT, german enigma 3 rotor cipher with fixed key
+ * @return 0 if ok, -1 if error (NULL buffer or unknown encryption type)
+ */
+int            pst_decrypt(uint64_t i_id, char *buf, size_t size, unsigned char type);
+
+
+/** Get an ID block from the file using pst_ff_getIDblock() and decrypt if necessary.
+ * @param pf   pointer to the pst_file structure setup by pst_open().
+ * @param i_id ID of block to retrieve
+ * @param buf  reference to pointer to buffer that will contain the data block.
+ *             If this pointer is non-NULL, it will first be free()d.
+ * @return     Size of block read into memory
+ */
+size_t         pst_ff_getIDblock_dec(pst_file *pf, uint64_t i_id, char **buf);
+
+
+/** Read a block of data from the file into memory.
+ * @param pf   pointer to the pst_file structure setup by pst_open().
+ * @param i_id ID of block to read
+ * @param buf  reference to pointer to buffer that will contain the data block.
+ *             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 i_id, char** buf);
+
+
+/** fwrite with checking for null pointer.
+ * @param ptr pointer to the buffer
+ * @param size  size of each item
+ * @param nmemb number of items
+ * @param stream output file
+ * @return number of bytes written, zero if ptr==NULL
+ */
+size_t         pst_fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream);
+
+
+/** Add any necessary escape characters for rfc2426 vcard format
+ * @param str pointer to input string
+ * @return    pointer to output string, either the input pointer if
+ *            there are no characters that need escapes, or a pointer
+ *            to a different buffer containing the escaped string. In
+ *            either case, you don't need to free this returned pointer.
+ */
 char *         pst_rfc2426_escape(char *str);
+
+
+/** Convert a FILETIME into rfc2425 date/time format 1953-10-15T23:10:00Z
+ *  which is the same as one of the forms in the ISO3601 standard
+ * @param ft time to be converted
+ * @return   time in rfc2425 format
+ */
 char *         pst_rfc2425_datetime_format(FILETIME *ft);
+
+
+/** Convert a FILETIME into rfc2445 date/time format 19531015T231000Z
+ * @param ft time to be converted
+ * @return   time in rfc2445 format
+ */
 char *         pst_rfc2445_datetime_format(FILETIME *ft);
 
 
 /** Convert a code page integer into a string suitable for iconv()
- *
- *  @param cp the code page integer used in the pst file
+ *  @param  cp the code page integer used in the pst file
  *  @return pointer to a static buffer holding the string representation of the
  *          equivalent iconv character set
  */
@@ -858,7 +1015,6 @@
 
 
 /** Convert str to utf8 if possible; null strings are preserved.
- *
  *  @param item  pointer to the containing mapi item
  *  @param str   pointer to the mapi string of interest
  */
@@ -866,7 +1022,6 @@
 
 
 /** Convert str to utf8 if possible; null strings are converted into empty strings.
- *
  *  @param item  pointer to the containing mapi item
  *  @param str   pointer to the mapi string of interest
  */
--- a/src/readpst.c	Tue Apr 14 22:26:17 2009 -0700
+++ b/src/readpst.c	Wed Apr 15 18:39:42 2009 -0700
@@ -1100,7 +1100,6 @@
     char sender[60];
     int  sender_known = 0;
     char *temp = NULL;
-    int attach_num;
     time_t em_time;
     char *c_time;
     char *headers = NULL;
@@ -1347,7 +1346,7 @@
     // other attachments
     {
         pst_item_attach* attach;
-        attach_num = 0;
+        int attach_num = 0;
         for (attach = item->attach; attach; attach = attach->next) {
             pst_convert_utf8_null(item, &attach->filename1);
             pst_convert_utf8_null(item, &attach->filename2);
--- a/xml/libpst.in	Tue Apr 14 22:26:17 2009 -0700
+++ b/xml/libpst.in	Wed Apr 15 18:39:42 2009 -0700
@@ -7,6 +7,8 @@
         url="http://www.five-ten-sg.com/@PACKAGE@/packages/">http://www.five-ten-sg.com/@PACKAGE@/packages/</ulink>.
         The most recent documentation is available at <ulink
         url="http://www.five-ten-sg.com/@PACKAGE@/">http://www.five-ten-sg.com/@PACKAGE@/</ulink>.
+        The most recent developer documentation for the shared library is available at <ulink
+        url="http://www.five-ten-sg.com/@PACKAGE@/">http://www.five-ten-sg.com/@PACKAGE@/devel/</ulink>.
         </para>
 
         <para>A <ulink
@@ -33,7 +35,7 @@
 
     <refentry id="readpst.1">
         <refentryinfo>
-            <date>2009-03-11</date>
+            <date>2009-04-15</date>
         </refentryinfo>
 
         <refmeta>
@@ -233,7 +235,7 @@
 
     <refentry id="lspst.1">
         <refentryinfo>
-            <date>2009-03-11</date>
+            <date>2009-04-15</date>
         </refentryinfo>
 
         <refmeta>
@@ -336,7 +338,7 @@
 
     <refentry id="readpstlog.1">
         <refentryinfo>
-            <date>2009-03-11</date>
+            <date>2009-04-15</date>
         </refentryinfo>
 
         <refmeta>
@@ -511,7 +513,7 @@
 
     <refentry id="pst2ldif.1">
         <refentryinfo>
-            <date>2009-03-11</date>
+            <date>2009-04-15</date>
         </refentryinfo>
 
         <refmeta>
@@ -680,7 +682,7 @@
 
     <refentry id="pst2dii.1">
         <refentryinfo>
-            <date>2009-03-11</date>
+            <date>2009-04-15</date>
         </refentryinfo>
 
         <refmeta>
@@ -814,7 +816,7 @@
 
     <refentry id="pst.5">
         <refentryinfo>
-            <date>2009-03-11</date>
+            <date>2009-04-15</date>
         </refentryinfo>
 
         <refmeta>