changeset 195:320cfcba8058

add python module interface to the shared library for easy scripting. the shared library must never write to stdout or stderr. fix pst_attach_to_mem so the caller does not need to initialize the buffer pointer.
author Carl Byington <carl@five-ten-sg.com>
date Mon, 20 Apr 2009 19:39:26 -0700
parents 885b47107036
children ffd1503a7530
files ChangeLog Makefile.am TODO configure.in python/Makefile.am python/python-libpst.cpp python/test.py regression/regression-tests.bash src/libpst.c src/libpst.h src/lspst.c src/pst2dii.cpp.in src/readpst.c src/vbuf.c
diffstat 14 files changed, 566 insertions(+), 124 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Fri Apr 17 13:08:31 2009 -0700
+++ b/ChangeLog	Mon Apr 20 19:39:26 2009 -0700
@@ -1,3 +1,10 @@
+LibPST 0.6.38 (2009-xx-xx)
+===============================
+    * add python module interface to the shared library for easy scripting.
+    * the shared library must never write to stdout or stderr.
+    * fix pst_attach_to_mem so the caller does not need to initialize
+      the buffer pointer.
+
 LibPST 0.6.37 (2009-04-17)
 ===============================
     * add pst_attach_to_mem() back into the shared library interface.
--- a/Makefile.am	Fri Apr 17 13:08:31 2009 -0700
+++ b/Makefile.am	Mon Apr 20 19:39:26 2009 -0700
@@ -1,4 +1,4 @@
-SUBDIRS = src man html debian
+SUBDIRS = src python man html debian
 htmldir = ${datadir}/doc/@PACKAGE@-@VERSION@
 html_DATA = AUTHORS COPYING ChangeLog NEWS README
 CLEANFILES = xml/libpst xml/Makefile
--- a/TODO	Fri Apr 17 13:08:31 2009 -0700
+++ b/TODO	Mon Apr 20 19:39:26 2009 -0700
@@ -9,4 +9,4 @@
     remove pst_x_attrib_ll->type (unused)
     reorder appointment fields to collect related fields
     remove readpstlog, and produce directly ascii debug log files
-
+    change pst_attach_to_mem to return pst_binary
--- a/configure.in	Fri Apr 17 13:08:31 2009 -0700
+++ b/configure.in	Mon Apr 20 19:39:26 2009 -0700
@@ -1,5 +1,5 @@
 AC_PREREQ(2.59)
-AC_INIT(libpst,0.6.37,carl@five-ten-sg.com)
+AC_INIT(libpst,0.6.38,carl@five-ten-sg.com)
 AC_CONFIG_SRCDIR([src/libpst.c])
 AC_CONFIG_HEADER([config.h])
 AM_INIT_AUTOMAKE
@@ -24,12 +24,22 @@
 libpst_so_major='2'
 AC_SUBST(LIBPST_SO_MAJOR, [$libpst_so_major])
 
+python_libpst_version_info='1:0:0'
+AC_SUBST(PYTHON_LIBPST_VERSION_INFO, [$python_libpst_version_info])
+python_libpst_so_major='2'
+AC_SUBST(PYTHON_LIBPST_SO_MAJOR, [$python_libpst_so_major])
+
 # 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
+# version   soname          so library name     python          python library name
+# 0.6.35    libpst.so.2     libpst.so.2.0.0
+# 0.6.37    libpst.so.2     libpst.so.2.1.0
+# 0.6.38    libpst.so.2     libpst.so.2.1.0     _libpst.so.1    _libpst.so.1.0.0
 
 
+# check for boost
+AX_PYTHON
+AX_BOOST_PYTHON
+
 
 # Check for win32
 AC_MSG_CHECKING([for Win32])
@@ -261,6 +271,7 @@
     man/Makefile            \
     src/Makefile            \
     src/pst2dii.cpp         \
+    python/Makefile         \
     xml/Makefile            \
     xml/libpst              \
     )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/Makefile.am	Mon Apr 20 19:39:26 2009 -0700
@@ -0,0 +1,13 @@
+if PLATFORM_WIN32
+    NO_UNDEFINED = -no-undefined
+else
+    NO_UNDEFINED =
+endif
+
+lib_LTLIBRARIES     = _libpst.la
+_libpst_la_LDFLAGS  = -module $(NO_UNDEFINED) -version-info @PYTHON_LIBPST_VERSION_INFO@
+_libpst_la_SOURCES  = python-libpst.cpp
+_libpst_la_LIBADD   = -lboost_python ../src/libpst.la
+
+# set the include path found by configure
+INCLUDES= -I$(srcdir)/.. -I$(srcdir)/../src $(all_includes) -I$(PYTHON_INCLUDE_DIR)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/python-libpst.cpp	Mon Apr 20 19:39:26 2009 -0700
@@ -0,0 +1,396 @@
+#ifdef HAVE_CONFIG_H
+    #include "config.h"
+#endif
+
+#include <iostream>
+#include <boost/python.hpp>
+#include <iostream>
+
+extern "C" {
+    #include "libpst.h"
+    #include "timeconv.h"
+    #include "libstrfunc.h"
+    #include "vbuf.h"
+    #include "lzfu.h"
+}
+
+using namespace std;
+using namespace boost::python;
+
+
+/** python version of pst_binary, where python is
+    responsible for freeing the underlying buffer */
+struct ppst_binary : public pst_binary
+{
+};
+
+class pst {
+public:
+                   pst(const string filename);
+    virtual        ~pst();
+    pst_desc_tree* pst_getTopOfFolders();
+    ppst_binary    pst_attach_to_mem(pst_item_attach *attach);
+    size_t         pst_attach_to_file(pst_item_attach *attach, FILE* fp);
+    size_t         pst_attach_to_file_base64(pst_item_attach *attach, FILE* fp);
+    pst_desc_tree* pst_getNextDptr(pst_desc_tree* d);
+    pst_item*      pst_parse_item(pst_desc_tree *d_ptr, pst_id2_tree *m_head);
+    void           pst_freeItem(pst_item *item);
+    pst_index_ll*  pst_getID(uint64_t i_id);
+    int            pst_decrypt(uint64_t i_id, char *buf, size_t size, unsigned char type);
+    size_t         pst_ff_getIDblock_dec(uint64_t i_id, char **buf);
+    size_t         pst_ff_getIDblock(uint64_t i_id, char** buf);
+    string         pst_rfc2426_escape(char *str);
+    string         pst_rfc2425_datetime_format(const FILETIME *ft);
+    string         pst_rfc2445_datetime_format(const FILETIME *ft);
+    string         pst_default_charset(pst_item *item);
+    void           pst_convert_utf8_null(pst_item *item, pst_string *str);
+    void           pst_convert_utf8(pst_item *item, pst_string *str);
+
+private:
+    bool            is_open;
+    pst_file        pf;
+    pst_item*       root;
+    pst_desc_tree*  topf;
+
+};
+
+
+pst::pst(const string filename) {
+    char *f = (char *)filename.c_str(); // ok, since pst_open does not actually modify this buffer, and newer versions will change the signature to const anyway
+    is_open = (::pst_open(&pf, f) == 0);
+    root = NULL;
+    topf = NULL;
+    if (is_open) {
+        ::pst_load_index(&pf);
+        ::pst_load_extended_attributes(&pf);
+        root = ::pst_parse_item(&pf, pf.d_head, NULL);
+        topf = ::pst_getTopOfFolders(&pf, root)->child;
+    }
+}
+
+pst::~pst() {
+    if (root) pst_freeItem(root);
+    if (is_open) ::pst_close(&pf);
+}
+
+pst_desc_tree* pst::pst_getTopOfFolders() {
+    return topf;
+}
+
+ppst_binary    pst::pst_attach_to_mem(pst_item_attach *attach) {
+    ppst_binary rc;
+    rc.size = rc.size = ::pst_attach_to_mem(&pf, attach, &rc.data);
+    return rc;
+}
+
+size_t         pst::pst_attach_to_file(pst_item_attach *attach, FILE* fp) {
+    return ::pst_attach_to_file(&pf, attach, fp);
+}
+
+size_t         pst::pst_attach_to_file_base64(pst_item_attach *attach, FILE* fp) {
+    return ::pst_attach_to_file_base64(&pf, attach, fp);
+}
+
+pst_desc_tree* pst::pst_getNextDptr(pst_desc_tree* d) {
+    return ::pst_getNextDptr(d);
+}
+
+pst_item*      pst::pst_parse_item (pst_desc_tree *d_ptr, pst_id2_tree *m_head) {
+    return ::pst_parse_item(&pf, d_ptr, m_head);
+}
+
+void           pst::pst_freeItem(pst_item *item) {
+    return ::pst_freeItem(item);
+}
+
+pst_index_ll*  pst::pst_getID(uint64_t i_id) {
+    return ::pst_getID(&pf, i_id);
+}
+
+int            pst::pst_decrypt(uint64_t i_id, char *buf, size_t size, unsigned char type) {
+    return ::pst_decrypt(i_id, buf, size, type);
+}
+
+size_t         pst::pst_ff_getIDblock_dec(uint64_t i_id, char **buf) {
+    return ::pst_ff_getIDblock_dec(&pf, i_id, buf);
+}
+
+size_t         pst::pst_ff_getIDblock(uint64_t i_id, char** buf) {
+    return ::pst_ff_getIDblock(&pf, i_id, buf);
+}
+
+string         pst::pst_rfc2426_escape(char *str) {
+    return ::pst_rfc2426_escape(str);
+}
+
+string         pst::pst_rfc2425_datetime_format(const FILETIME *ft) {
+    return ::pst_rfc2425_datetime_format((FILETIME *)ft);   // cast away const is ok, since libpst did not modify it anyway, and the signature will change in more recent versions
+}
+
+string         pst::pst_rfc2445_datetime_format(const FILETIME *ft) {
+    return ::pst_rfc2445_datetime_format((FILETIME *)ft);   // cast away const is ok, since libpst did not modify it anyway, and the signature will change in more recent versions
+}
+
+string         pst::pst_default_charset(pst_item *item) {
+    return ::pst_default_charset(item);
+}
+
+void           pst::pst_convert_utf8_null(pst_item *item, pst_string *str) {
+    ::pst_convert_utf8_null(item, str);
+}
+
+void           pst::pst_convert_utf8(pst_item *item, pst_string *str) {
+    ::pst_convert_utf8(item, str);
+}
+
+struct make_python_string {
+    /* we make no distinction between empty and null strings */
+    static PyObject* convert(char* const &s) {
+        string ss;
+        if (s) ss = string(s);
+        return boost::python::incref(boost::python::object(ss).ptr());
+    }
+};
+
+struct make_python_pst_binary {
+    static PyObject* convert(pst_binary const &s) {
+        if (s.data) {
+            string ss;
+            ss = string(s.data, s.size);
+            return boost::python::incref(boost::python::object(ss).ptr());
+        }
+        return NULL;
+    }
+};
+
+struct make_python_ppst_binary {
+    static PyObject* convert(ppst_binary const &s) {
+        if (s.data) {
+            string ss;
+            ss = string(s.data, s.size);
+            free(s.data);
+            return boost::python::incref(boost::python::object(ss).ptr());
+        }
+        return NULL;
+    }
+};
+
+struct make_python_pst_item_email {
+    static PyObject* convert(pst_item_email* const &s) {
+        if (s) return to_python_indirect<pst_item_email*, detail::make_reference_holder>()(s);
+        return NULL;
+    }
+};
+
+struct make_python_pst_item_attach {
+    static PyObject* convert(pst_item_attach* const &s) {
+        if (s) return to_python_indirect<pst_item_attach*, detail::make_reference_holder>()(s);
+        return NULL;
+    }
+};
+
+struct make_python_pst_desc_tree {
+    static PyObject* convert(pst_desc_tree* const &s) {
+        if (s) return to_python_indirect<pst_desc_tree*, detail::make_reference_holder>()(s);
+        return NULL;
+    }
+};
+
+struct make_python_pst_index_ll {
+    static PyObject* convert(pst_index_ll* const &s) {
+        if (s) return to_python_indirect<pst_index_ll*, detail::make_reference_holder>()(s);
+        return NULL;
+    }
+};
+
+BOOST_PYTHON_MODULE(_libpst)
+{
+    to_python_converter<pst_binary,       make_python_pst_binary>();
+    to_python_converter<ppst_binary,      make_python_ppst_binary>();
+    to_python_converter<char*,            make_python_string>();
+    to_python_converter<pst_item_email*,  make_python_pst_item_email>();
+    to_python_converter<pst_item_attach*, make_python_pst_item_attach>();
+    to_python_converter<pst_desc_tree*,   make_python_pst_desc_tree>();
+    to_python_converter<pst_index_ll*,    make_python_pst_index_ll>();
+
+    class_<FILETIME>("FILETIME")
+        .def_readonly("dwLowDateTime",  &FILETIME::dwLowDateTime)
+        .def_readonly("dwHighDateTime", &FILETIME::dwHighDateTime)
+        ;
+
+    class_<pst_entryid>("pst_entryid")
+        .def_readonly("u1",      &pst_entryid::u1)
+        .def_readonly("entryid", &pst_entryid::entryid)
+        .def_readonly("id",      &pst_entryid::id)
+        ;
+
+    class_<pst_index_ll>("pst_index_ll")
+        .def_readonly("i_id",               &pst_index_ll::i_id)
+        .def_readonly("offset",             &pst_index_ll::offset)
+        .def_readonly("size",               &pst_index_ll::size)
+        .def_readonly("u1",                 &pst_index_ll::u1)
+        .add_property("next",   make_getter(&pst_index_ll::next, return_value_policy<reference_existing_object>()))
+        ;
+
+    class_<pst_id2_tree>("pst_id2_tree")
+        .def_readonly("id2",               &pst_id2_tree::id2)
+        .add_property("id",    make_getter(&pst_id2_tree::id,    return_value_policy<reference_existing_object>()))
+        .add_property("child", make_getter(&pst_id2_tree::child, return_value_policy<reference_existing_object>()))
+        .add_property("next",  make_getter(&pst_id2_tree::next,  return_value_policy<reference_existing_object>()))
+        ;
+
+    class_<pst_desc_tree>("pst_desc_tree")
+        .def_readonly("d_id",                    &pst_desc_tree::d_id)
+        .def_readonly("parent_d_id",             &pst_desc_tree::parent_d_id)
+        .add_property("desc",        make_getter(&pst_desc_tree::desc,       return_value_policy<reference_existing_object>()))
+        .add_property("assoc_tree",  make_getter(&pst_desc_tree::assoc_tree, return_value_policy<reference_existing_object>()))
+        .def_readonly("no_child",                &pst_desc_tree::no_child)
+        .add_property("prev",        make_getter(&pst_desc_tree::prev,       return_value_policy<reference_existing_object>()))
+        .add_property("next",        make_getter(&pst_desc_tree::next,       return_value_policy<reference_existing_object>()))
+        .add_property("parent",      make_getter(&pst_desc_tree::parent,     return_value_policy<reference_existing_object>()))
+        .add_property("child",       make_getter(&pst_desc_tree::child,      return_value_policy<reference_existing_object>()))
+        .add_property("child_tail",  make_getter(&pst_desc_tree::child_tail, return_value_policy<reference_existing_object>()))
+        ;
+
+    class_<pst_string>("pst_string")
+        .def_readonly("is_utf8", &pst_string::is_utf8)
+        .def_readonly("str",     &pst_string::str)
+        ;
+
+    class_<pst_item_email>("pst_item_email")
+        .add_property("arrival_date", make_getter(&pst_item_email::arrival_date, return_value_policy<reference_existing_object>()))
+        .def_readonly("autoforward",              &pst_item_email::autoforward)
+        .def_readonly("cc_address",               &pst_item_email::cc_address)
+        .def_readonly("bcc_address",              &pst_item_email::bcc_address)
+        .def_readonly("conversation_index",       &pst_item_email::conversation_index)
+        .def_readonly("conversion_prohibited",    &pst_item_email::conversion_prohibited)
+        .def_readonly("delete_after_submit",      &pst_item_email::delete_after_submit)
+        .def_readonly("delivery_report",          &pst_item_email::delivery_report)
+        .def_readonly("encrypted_body",           &pst_item_email::encrypted_body)
+        .def_readonly("encrypted_htmlbody",       &pst_item_email::encrypted_htmlbody)
+        .def_readonly("header",                   &pst_item_email::header)
+        .def_readonly("htmlbody",                 &pst_item_email::htmlbody)
+        .def_readonly("importance",               &pst_item_email::importance)
+        .def_readonly("in_reply_to",              &pst_item_email::in_reply_to)
+        .def_readonly("message_cc_me",            &pst_item_email::message_cc_me)
+        .def_readonly("message_recip_me",         &pst_item_email::message_recip_me)
+        .def_readonly("message_to_me",            &pst_item_email::message_to_me)
+        .def_readonly("messageid",                &pst_item_email::messageid)
+        .def_readonly("original_sensitivity",     &pst_item_email::original_sensitivity)
+        .def_readonly("original_bcc",             &pst_item_email::original_bcc)
+        .def_readonly("original_cc",              &pst_item_email::original_cc)
+        .def_readonly("original_to",              &pst_item_email::original_to)
+        ;
+
+    class_<pst_item_folder>("pst_item_folder")
+        .def_readonly("item_count", &pst_item_folder::item_count)
+        ;
+
+    class_<pst_item_message_store>("pst_item_message_store")
+        .add_property("top_of_personal_folder", make_getter(&pst_item_message_store::top_of_personal_folder, return_value_policy<reference_existing_object>()))
+        ;
+
+    class_<pst_item_contact>("pst_item_contact")
+        .def_readonly("account_name", &pst_item_contact::account_name)
+        ;
+
+    class_<pst_item_attach>("pst_item_attach")
+        .def_readonly("filename1",             &pst_item_attach::filename1)
+        .def_readonly("filename2",             &pst_item_attach::filename2)
+        .def_readonly("mimetype",              &pst_item_attach::mimetype)
+        .def_readonly("data",                  &pst_item_attach::data)
+        .def_readonly("id2_val",               &pst_item_attach::id2_val)
+        .def_readonly("i_id",                  &pst_item_attach::i_id)
+        .add_property("id2_head",  make_getter(&pst_item_attach::id2_head, return_value_policy<reference_existing_object>()))
+        .def_readonly("method",                &pst_item_attach::method)
+        .def_readonly("position",              &pst_item_attach::position)
+        .def_readonly("sequence",              &pst_item_attach::sequence)
+        .add_property("next",      make_getter(&pst_item_attach::next, return_value_policy<reference_existing_object>()))
+        ;
+
+    class_<pst_item_extra_field>("pst_item_extra_field")
+        .def_readonly("field_name", &pst_item_extra_field::field_name)
+        ;
+
+    class_<pst_item_journal>("pst_item_journal")
+        .def_readonly("description", &pst_item_journal::description)
+        ;
+
+    class_<pst_item_appointment>("pst_item_appointment")
+        .add_property("end",   make_getter(&pst_item_appointment::end, return_value_policy<reference_existing_object>()))
+        .def_readonly("label", &pst_item_appointment::label)
+        ;
+
+    class_<pst_item>("pst_item")
+        .add_property("email",           make_getter(&pst_item::email,         return_value_policy<reference_existing_object>()))
+        .add_property("folder",          make_getter(&pst_item::folder,        return_value_policy<reference_existing_object>()))
+        .add_property("contact",         make_getter(&pst_item::contact,       return_value_policy<reference_existing_object>()))
+        .add_property("attach",          make_getter(&pst_item::attach,        return_value_policy<reference_existing_object>()))
+        .add_property("message_store",   make_getter(&pst_item::message_store, return_value_policy<reference_existing_object>()))
+        .add_property("extra_fields",    make_getter(&pst_item::extra_fields,  return_value_policy<reference_existing_object>()))
+        .add_property("journal",         make_getter(&pst_item::journal,       return_value_policy<reference_existing_object>()))
+        .add_property("appointment",     make_getter(&pst_item::appointment,   return_value_policy<reference_existing_object>()))
+        .def_readonly("type",                        &pst_item::type)
+        .def_readonly("ascii_type",                  &pst_item::ascii_type)
+        .def_readonly("flags",                       &pst_item::flags)
+        .def_readonly("file_as",                     &pst_item::file_as)
+        .def_readonly("comment",                     &pst_item::comment)
+        .def_readonly("body_charset",                &pst_item::body_charset)
+        .def_readonly("body",                        &pst_item::body)
+        .def_readonly("subject",                     &pst_item::subject)
+        .def_readonly("internet_cpid",               &pst_item::internet_cpid)
+        .def_readonly("message_codepage",            &pst_item::message_codepage)
+        .def_readonly("message_size",                &pst_item::message_size)
+        .def_readonly("outlook_version",             &pst_item::outlook_version)
+        .def_readonly("record_key",                  &pst_item::record_key)
+        .def_readonly("predecessor_change",          &pst_item::predecessor_change)
+        .def_readonly("response_requested",          &pst_item::response_requested)
+        .add_property("create_date",     make_getter(&pst_item::create_date, return_value_policy<reference_existing_object>()))
+        .add_property("modify_date",     make_getter(&pst_item::modify_date, return_value_policy<reference_existing_object>()))
+        .def_readonly("private_member",              &pst_item::private_member)
+        ;
+
+    class_<pst_x_attrib_ll>("pst_x_attrib_ll")
+        .def_readonly("mytype", &pst_x_attrib_ll::mytype)
+        .def_readonly("map",    &pst_x_attrib_ll::map)
+        .def_readonly("data",   &pst_x_attrib_ll::data)
+        .def_readonly("next",   &pst_x_attrib_ll::next)
+        ;
+
+    class_<pst_file>("pst_file")
+        .add_property("i_head",      make_getter(&pst_file::i_head, return_value_policy<reference_existing_object>()))
+        .add_property("i_tail",      make_getter(&pst_file::i_tail, return_value_policy<reference_existing_object>()))
+        .add_property("d_head",      make_getter(&pst_file::d_head, return_value_policy<reference_existing_object>()))
+        .add_property("d_tail",      make_getter(&pst_file::d_tail, return_value_policy<reference_existing_object>()))
+        .def_readonly("do_read64",   &pst_file::do_read64)
+        .def_readonly("index1",      &pst_file::index1)
+        .def_readonly("index1_back", &pst_file::index1_back)
+        .def_readonly("index2",      &pst_file::index2)
+        .def_readonly("index2_back", &pst_file::index2_back)
+        .def_readonly("size",        &pst_file::size)
+        .def_readonly("encryption",  &pst_file::encryption)
+        .def_readonly("ind_type",    &pst_file::ind_type)
+        ;
+
+    class_<pst>("pst", init<string>())
+        .def("pst_getTopOfFolders",         &pst::pst_getTopOfFolders, return_value_policy<reference_existing_object>())
+        .def("pst_attach_to_mem",           &pst::pst_attach_to_mem)
+        .def("pst_attach_to_file",          &pst::pst_attach_to_file)
+        .def("pst_attach_to_file_base64",   &pst::pst_attach_to_file_base64)
+        .def("pst_getNextDptr",             &pst::pst_getNextDptr,     return_value_policy<reference_existing_object>())
+        .def("pst_parse_item",              &pst::pst_parse_item,      return_value_policy<reference_existing_object>())
+        .def("pst_freeItem",                &pst::pst_freeItem)
+        .def("pst_getID",                   &pst::pst_getID,           return_value_policy<reference_existing_object>())
+        .def("pst_decrypt",                 &pst::pst_decrypt)
+        .def("pst_ff_getIDblock_dec",       &pst::pst_ff_getIDblock_dec)
+        .def("pst_ff_getIDblock",           &pst::pst_ff_getIDblock)
+        .def("pst_rfc2426_escape",          &pst::pst_rfc2426_escape)
+        .def("pst_rfc2425_datetime_format", &pst::pst_rfc2425_datetime_format)
+        .def("pst_rfc2445_datetime_format", &pst::pst_rfc2445_datetime_format)
+        .def("pst_default_charset",         &pst::pst_default_charset)
+        .def("pst_convert_utf8_null",       &pst::pst_convert_utf8_null)
+        .def("pst_convert_utf8",            &pst::pst_convert_utf8)
+        ;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/python/test.py	Mon Apr 20 19:39:26 2009 -0700
@@ -0,0 +1,36 @@
+import _libpst, sys
+
+for i in range(1,len(sys.argv)):
+    print "try file %s" % (sys.argv[i])
+    pst = _libpst.pst(sys.argv[i])
+    topf = pst.pst_getTopOfFolders()
+
+    while (topf):
+        #print "topf d_id is %d\n" % (topf.d_id)
+        item = pst.pst_parse_item(topf, None)
+        if (item):
+            if (item.type == 1):
+                em = item.email
+                if (em):
+                    if (em.messageid.str):
+                        print "message id is |%s|" % (em.messageid.str)
+                    subj = item.subject;
+                    if (subj.str):
+                        print "subject is %s" % (subj.str)
+                    body = item.body
+                    #if (body.str):
+                    #    print "message body is %s" % (body.str)
+                    att = item.attach
+                    while (att):
+                        attid   = att.i_id
+                        print "attachment id %d" % (attid)
+                        att1 = att.filename1
+                        att2 = att.filename2
+                        print "attachment file name %s %s" % (att1.str, att2.str)
+                        attdata = pst.pst_attach_to_mem(att)
+                        if (attdata):
+                            print "data size %d" % (len(attdata))
+                        att = att.next
+        topf = pst.pst_getNextDptr(topf)
+    print "done"
+
--- a/regression/regression-tests.bash	Fri Apr 17 13:08:31 2009 -0700
+++ b/regression/regression-tests.bash	Mon Apr 20 19:39:26 2009 -0700
@@ -65,7 +65,7 @@
 
 
 val="valgrind --leak-check=full"
-#val=''
+val=''
 
 pushd ..
 make || exit
--- a/src/libpst.c	Fri Apr 17 13:08:31 2009 -0700
+++ b/src/libpst.c	Mon Apr 20 19:39:26 2009 -0700
@@ -284,7 +284,7 @@
 
 
 
-int pst_open(pst_file *pf, char *name) {
+int pst_open(pst_file *pf, const char *name) {
     int32_t sig;
 
     pst_unicode_init();
@@ -307,7 +307,7 @@
     // Check pst file magic
     if (pst_getAtPos(pf, 0, &sig, sizeof(sig)) != sizeof(sig)) {
         (void)fclose(pf->fp);
-        WARN(("cannot read signature from PST file. Closing on error\n"));
+        DEBUG_WARN(("cannot read signature from PST file. Closing with error\n"));
         DEBUG_RET();
         return -1;
     }
@@ -315,7 +315,7 @@
     DEBUG_INFO(("sig = %X\n", sig));
     if (sig != (int32_t)PST_SIGNATURE) {
         (void)fclose(pf->fp);
-        WARN(("not a PST file that I know. Closing with error\n"));
+        DEBUG_WARN(("not a PST file that I know. Closing with error\n"));
         DEBUG_RET();
         return -1;
     }
@@ -334,7 +334,7 @@
             break;
         default:
             (void)fclose(pf->fp);
-            WARN(("unknown .pst format, possibly newer than Outlook 2003 PST file?\n"));
+            DEBUG_WARN(("unknown .pst format, possibly newer than Outlook 2003 PST file?\n"));
             DEBUG_RET();
             return -1;
     }
@@ -360,12 +360,11 @@
 int pst_close(pst_file *pf) {
     DEBUG_ENT("pst_close");
     if (!pf->fp) {
-        WARN(("cannot close NULL fp\n"));
         DEBUG_RET();
-        return -1;
+        return 0;
     }
     if (fclose(pf->fp)) {
-        WARN(("fclose returned non-zero value\n"));
+        DEBUG_WARN(("fclose returned non-zero value\n"));
         DEBUG_RET();
         return -1;
     }
@@ -487,7 +486,7 @@
 }
 
 
-pst_desc_tree* pst_getTopOfFolders(pst_file *pf, pst_item *root) {
+pst_desc_tree* pst_getTopOfFolders(pst_file *pf, const pst_item *root) {
     pst_desc_tree *topnode;
     uint32_t topid;
     DEBUG_ENT("pst_getTopOfFolders");
@@ -523,18 +522,21 @@
     pst_index_ll *ptr;
     pst_holder h = {b, NULL, 0};
     size_t size = 0;
+    *b = NULL;
     DEBUG_ENT("pst_attach_to_mem");
-    if (attach->i_id != (uint64_t)-1) {
+    if ((!attach->data.data) && (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"));
+            *b = NULL;
         }
-        attach->data.size = size;
     } else {
         size = attach->data.size;
         *b   = attach->data.data;
+        attach->data.data = NULL;   // prevent pst_free_item() from trying to free this
+        attach->data.size = 0;      // since we have given that buffer to the caller
     }
     DEBUG_RET();
     return size;
@@ -546,18 +548,19 @@
     pst_holder h = {NULL, fp, 0};
     size_t size = 0;
     DEBUG_ENT("pst_attach_to_file");
-    if (attach->i_id != (uint64_t)-1) {
+    if ((!attach->data.data) && (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 save attachment to file\n"));
         }
-        attach->data.size = size;
     } else {
-        // save the attachment to the file
         size = attach->data.size;
-        (void)pst_fwrite(attach->data.data, (size_t)1, size, fp);
+        if (attach->data.data && size) {
+            // save the attachment to the file
+            (void)pst_fwrite(attach->data.data, (size_t)1, size, fp);
+        }
     }
     DEBUG_RET();
     return size;
@@ -569,21 +572,22 @@
     pst_holder h = {NULL, fp, 1};
     size_t size = 0;
     DEBUG_ENT("pst_attach_to_file_base64");
-    if (attach->i_id != (uint64_t)-1) {
+    if ((!attach->data.data) && (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 save attachment to Base64\n"));
         }
-        attach->data.size = size;
     } else {
-        // encode the attachment to the file
         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
+        if (attach->data.data && size) {
+            // encode the attachment to the file
+            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
+            }
         }
     }
     DEBUG_RET();
@@ -595,7 +599,7 @@
     int  x;
     DEBUG_ENT("pst_load_index");
     if (!pf) {
-        WARN(("Cannot load index for a NULL pst_file\n"));
+        DEBUG_WARN(("Cannot load index for a NULL pst_file\n"));
         DEBUG_RET();
         return -1;
     }
@@ -1425,7 +1429,7 @@
 
     DEBUG_ENT("pst_parse_block");
     if ((read_size = pst_ff_getIDblock_dec(pf, block_id, &buf)) == 0) {
-        WARN(("Error reading block id %#"PRIx64"\n", block_id));
+        DEBUG_WARN(("Error reading block id %#"PRIx64"\n", block_id));
         if (buf) free (buf);
         DEBUG_RET();
         return NULL;
@@ -1496,7 +1500,7 @@
         DEBUG_EMAIL(("table_rec (type=%#hx, ref_type=%#hx, value=%#x)\n", table_rec.type, table_rec.ref_type, table_rec.value));
 
         if ((table_rec.type != (uint16_t)0x02B5) || (table_rec.ref_type != 6)) {
-            WARN(("Unknown second block constant - %#hx %#hx for id %#"PRIx64"\n", table_rec.type, table_rec.ref_type, block_id));
+            DEBUG_WARN(("Unknown second block constant - %#hx %#hx for id %#"PRIx64"\n", table_rec.type, table_rec.ref_type, block_id));
             freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
             DEBUG_RET();
             return NULL;
@@ -1537,7 +1541,7 @@
         list_start = fr_ptr + sizeof(seven_c_blk); // the list of item numbers start after this record
 
         if (seven_c_blk.seven_c != 0x7C) { // this would mean it isn't a 7C block!
-            WARN(("Error. There isn't a 7C where I want to see 7C!\n"));
+            DEBUG_WARN(("Error. There isn't a 7C where I want to see 7C!\n"));
             freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
             DEBUG_RET();
             return NULL;
@@ -1559,7 +1563,7 @@
         DEBUG_EMAIL(("table_rec (type=%#hx, ref_type=%#hx, value=%#x)\n", table_rec.type, table_rec.ref_type, table_rec.value));
 
         if (table_rec.type != (uint16_t)0x04B5) { // different constant than a type 1 record
-            WARN(("Unknown second block constant - %#hx for id %#"PRIx64"\n", table_rec.type, block_id));
+            DEBUG_WARN(("Unknown second block constant - %#hx for id %#"PRIx64"\n", table_rec.type, block_id));
             freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
             DEBUG_RET();
             return NULL;
@@ -1585,7 +1589,7 @@
         ind2_end = block_offset6.to;
     }
     else {
-        WARN(("ERROR: Unknown block constant - %#hx for id %#"PRIx64"\n", block_hdr.type, block_id));
+        DEBUG_WARN(("ERROR: Unknown block constant - %#hx for id %#"PRIx64"\n", block_hdr.type, block_id));
         freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
         DEBUG_RET();
         return NULL;
@@ -1646,7 +1650,7 @@
                 }
                 fr_ptr += sizeof(table2_rec);
             } else {
-                WARN(("Missing code for block_type %i\n", block_type));
+                DEBUG_WARN(("Missing code for block_type %i\n", block_type));
                 freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
                 pst_free_list(mo_head);
                 DEBUG_RET();
@@ -1786,7 +1790,7 @@
                     DEBUG_HEXDUMPC(utf16buf->b, utf16buf->dlen, 0x10);
                     rc = pst_vb_utf16to8(utf8buf, utf16buf->b, utf16buf->dlen);
                     if (rc == (size_t)-1) {
-                        DEBUG_EMAIL(("Failed to convert utf-16 to utf-8\n"));
+                        DEBUG_WARN(("Failed to convert utf-16 to utf-8\n"));
                     }
                     else {
                         free(mo_ptr->elements[x]->data);
@@ -1799,7 +1803,7 @@
                 }
                 if (mo_ptr->elements[x]->type == 0) mo_ptr->elements[x]->type = table_rec.ref_type;
             } else {
-                WARN(("ERROR Unknown ref_type %#hx\n", table_rec.ref_type));
+                DEBUG_WARN(("ERROR Unknown ref_type %#hx\n", table_rec.ref_type));
                 freeall(&subblocks, &block_offset1, &block_offset2, &block_offset3, &block_offset4, &block_offset5, &block_offset6, &block_offset7);
                 pst_free_list(mo_head);
                 DEBUG_RET();
@@ -1843,7 +1847,7 @@
         LIST_COPY(targ, (char*))                                            \
     }                                                                       \
     else {                                                                  \
-        DEBUG_EMAIL(("src not 0x1e or 0x1f or 0x102 for string dst\n"));    \
+        DEBUG_WARN(("src not 0x1e or 0x1f or 0x102 for string dst\n"));    \
         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);    \
         SAFE_FREE(targ);                                                    \
         targ = NULL;                                                        \
@@ -1852,7 +1856,7 @@
 
 #define LIST_COPY_BOOL(label, targ) {                                       \
     if (list->elements[x]->type != 0x0b) {                                  \
-        DEBUG_EMAIL(("src not 0x0b for boolean dst\n"));                    \
+        DEBUG_WARN(("src not 0x0b for boolean dst\n"));                    \
         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);    \
     }                                                                       \
     if (*(int16_t*)list->elements[x]->data) {                               \
@@ -1881,7 +1885,7 @@
 
 #define LIST_COPY_INT16_N(targ) {                                           \
     if (list->elements[x]->type != 0x02) {                                  \
-        DEBUG_EMAIL(("src not 0x02 for int16 dst\n"));                      \
+        DEBUG_WARN(("src not 0x02 for int16 dst\n"));                      \
         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);    \
     }                                                                       \
     memcpy(&(targ), list->elements[x]->data, sizeof(targ));                 \
@@ -1895,7 +1899,7 @@
 
 #define LIST_COPY_INT32_N(targ) {                                           \
     if (list->elements[x]->type != 0x03) {                                  \
-        DEBUG_EMAIL(("src not 0x03 for int32 dst\n"));                      \
+        DEBUG_WARN(("src not 0x03 for int32 dst\n"));                      \
         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);    \
     }                                                                       \
     memcpy(&(targ), list->elements[x]->data, sizeof(targ));                 \
@@ -2011,7 +2015,7 @@
 // malloc space and copy the item filetime
 #define LIST_COPY_TIME(label, targ) {                                       \
     if (list->elements[x]->type != 0x40) {                                  \
-        DEBUG_EMAIL(("src not 0x40 for filetime dst\n"));                   \
+        DEBUG_WARN(("src not 0x40 for filetime dst\n"));                   \
         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);    \
     }                                                                       \
     targ = (FILETIME*) realloc(targ, sizeof(FILETIME));                     \
@@ -2060,7 +2064,7 @@
     DEBUG_EMAIL((label"\n"));                       \
 }
 
-#define NULL_CHECK(x) { if (!x) { DEBUG_EMAIL(("NULL_CHECK: Null Found\n")); break;} }
+#define NULL_CHECK(x) { if (!x) { DEBUG_WARN(("NULL_CHECK: Null Found\n")); break;} }
 
 
 /**
@@ -2120,7 +2124,7 @@
                             }
                         }
                         else {
-                            DEBUG_EMAIL(("What does this mean? Internet header %s value\n", list->elements[x]->extra));
+                            DEBUG_WARN(("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
                         }
@@ -2132,7 +2136,7 @@
                         LIST_COPY_EMAIL_BOOL("AutoForward allowed", item->email->autoforward);
                         if (!item->email->autoforward) item->email->autoforward = -1;
                     } else {
-                        DEBUG_EMAIL(("What does this mean?\n"));
+                        DEBUG_WARN(("What does this mean?\n"));
                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
                     }
                     break;
@@ -2173,7 +2177,7 @@
                         DEBUG_EMAIL(("Message class %s [%"PRIi32"] \n", item->ascii_type, item->type));
                     }
                     else {
-                        DEBUG_EMAIL(("What does this mean?\n"));
+                        DEBUG_WARN(("What does this mean?\n"));
                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
                     }
                     break;
@@ -2183,7 +2187,7 @@
                         LIST_COPY_EMAIL_BOOL("Global Delivery Report", item->email->delivery_report);
                     }
                     else {
-                        DEBUG_EMAIL(("What does this mean?\n"));
+                        DEBUG_WARN(("What does this mean?\n"));
                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
                     }
                     break;
@@ -2227,25 +2231,25 @@
                     LIST_COPY_EMAIL_STR("Sent on behalf of address 1", item->email->outlook_sender);
                     break;
                 case 0x003F: // PR_RECEIVED_BY_ENTRYID Structure containing Recipient
-                    DEBUG_EMAIL(("Recipient Structure 1 -- NOT HANDLED\n"));
+                    DEBUG_EMAIL(("Recipient Structure 1 -- NOT PROCESSED\n"));
                     break;
                 case 0x0040: // PR_RECEIVED_BY_NAME Name of Recipient Structure
-                    DEBUG_EMAIL(("Received By Name 1 -- NOT HANDLED\n"));
+                    DEBUG_EMAIL(("Received By Name 1 -- NOT PROCESSED\n"));
                     break;
                 case 0x0041: // PR_SENT_REPRESENTING_ENTRYID Structure containing Sender
-                    DEBUG_EMAIL(("Sent on behalf of Structure 1 -- NOT HANDLED\n"));
+                    DEBUG_EMAIL(("Sent on behalf of Structure 1 -- NOT PROCESSED\n"));
                     break;
                 case 0x0042: // PR_SENT_REPRESENTING_NAME
                     LIST_COPY_EMAIL_STR("Sent on behalf of", item->email->outlook_sender_name);
                     break;
                 case 0x0043: // PR_RCVD_REPRESENTING_ENTRYID Recipient Structure 2
-                    DEBUG_EMAIL(("Received on behalf of Structure -- NOT HANDLED\n"));
+                    DEBUG_EMAIL(("Received on behalf of Structure -- NOT PROCESSED\n"));
                     break;
                 case 0x0044: // PR_RCVD_REPRESENTING_NAME
                     LIST_COPY_EMAIL_STR("Received on behalf of", item->email->outlook_recipient_name);
                     break;
                 case 0x004F: // PR_REPLY_RECIPIENT_ENTRIES Reply-To Structure
-                    DEBUG_EMAIL(("Reply-To Structure -- NOT HANDLED\n"));
+                    DEBUG_EMAIL(("Reply-To Structure -- NOT PROCESSED\n"));
                     break;
                 case 0x0050: // PR_REPLY_RECIPIENT_NAMES Name of Reply-To Structure
                     LIST_COPY_EMAIL_STR("Reply-To", item->email->reply_to);
@@ -2314,16 +2318,16 @@
                     LIST_COPY_EMAIL_INT32("NDR diag code", item->email->ndr_diag_code);
                     break;
                 case 0x0C06: // PR_NON_RECEIPT_NOTIFICATION_REQUESTED
-                    DEBUG_EMAIL(("Non-Receipt Notification Requested - (ignored) - "));
+                    DEBUG_EMAIL(("Non-Receipt Notification Requested -- NOT PROCESSED\n"));
                     break;
                 case 0x0C17: // PR_REPLY_REQUESTED
                     LIST_COPY_EMAIL_BOOL("Reply Requested", item->email->reply_requested);
                     break;
                 case 0x0C19: // PR_SENDER_ENTRYID Sender Structure 2
-                    DEBUG_EMAIL(("Sender Structure 2 -- NOT HANDLED\n"));
+                    DEBUG_EMAIL(("Sender Structure 2 -- NOT PROCESSED\n"));
                     break;
                 case 0x0C1A: // PR_SENDER_NAME Name of Sender Structure 2
-                    DEBUG_EMAIL(("Name of Sender Structure 2 -- NOT HANDLED\n"));
+                    DEBUG_EMAIL(("Name of Sender Structure 2 -- NOT PROCESSED\n"));
                     break;
                 case 0x0C1B: // PR_SUPPLEMENTARY_INFO
                     LIST_COPY_EMAIL_STR("Supplementary info", item->email->supplementary_info);
@@ -2443,7 +2447,7 @@
                     LIST_COPY_TIME("Date 5 (Modify Date)", item->modify_date);
                     break;
                 case 0x300B: // PR_SEARCH_KEY Record Header 2
-                    DEBUG_EMAIL(("Record Search 2 -- NOT HANDLED\n"));
+                    DEBUG_EMAIL(("Record Search 2 -- NOT PROCESSED\n"));
                     break;
                 case 0x35DF: // PR_VALID_FOLDER_MASK
                     LIST_COPY_STORE_INT32("Valid Folder Mask", item->message_store->valid_mask);
@@ -2648,7 +2652,7 @@
                     LIST_COPY_CONTACT_STR("Pager Phone Number", item->contact->pager_phone);
                     break;
                 case 0x3A22: // PR_USER_CERTIFICATE
-                    DEBUG_EMAIL(("User Certificate - NOT PROCESSED"));
+                    DEBUG_EMAIL(("User Certificate - NOT PROCESSED\n"));
                     break;
                 case 0x3A23: // PR_PRIMARY_FAX_NUMBER
                     LIST_COPY_CONTACT_STR("Primary Fax Number", item->contact->primary_fax);
@@ -2808,7 +2812,7 @@
                         attach->id2_val = tempid;
                         DEBUG_EMAIL(("%#"PRIx64"\n", attach->id2_val));
                     } else {
-                        DEBUG_EMAIL(("NOT AN ATTACHMENT: %#x\n", list->elements[x]->mapi_id));
+                        DEBUG_WARN(("NOT AN ATTACHMENT: %#x\n", list->elements[x]->mapi_id));
                     }
                     break;
                 case 0x67FF: // Extra Property Identifier (Password CheckSum)
@@ -2986,102 +2990,102 @@
                     break;
                 default:
                     if (list->elements[x]->type == (uint32_t)0x0002) {
-                        DEBUG_EMAIL(("Unknown type %#x 16bit int = %hi\n", list->elements[x]->mapi_id,
+                        DEBUG_WARN(("Unknown type %#x 16bit int = %hi\n", list->elements[x]->mapi_id,
                             *(int16_t*)list->elements[x]->data));
 
                     } else if (list->elements[x]->type == (uint32_t)0x0003) {
-                        DEBUG_EMAIL(("Unknown type %#x 32bit int = %i\n", list->elements[x]->mapi_id,
+                        DEBUG_WARN(("Unknown type %#x 32bit int = %i\n", list->elements[x]->mapi_id,
                             *(int32_t*)list->elements[x]->data));
 
                     } else if (list->elements[x]->type == (uint32_t)0x0004) {
-                        DEBUG_EMAIL(("Unknown type %#x 4-byte floating [size = %#x]\n", list->elements[x]->mapi_id,
+                        DEBUG_WARN(("Unknown type %#x 4-byte floating [size = %#x]\n", list->elements[x]->mapi_id,
                             list->elements[x]->size));
                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
 
                     } else if (list->elements[x]->type == (uint32_t)0x0005) {
-                        DEBUG_EMAIL(("Unknown type %#x double floating [size = %#x]\n", list->elements[x]->mapi_id,
+                        DEBUG_WARN(("Unknown type %#x double floating [size = %#x]\n", list->elements[x]->mapi_id,
                             list->elements[x]->size));
                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
 
                     } else if (list->elements[x]->type == (uint32_t)0x0006) {
-                        DEBUG_EMAIL(("Unknown type %#x signed 64bit int = %"PRIi64"\n", list->elements[x]->mapi_id,
+                        DEBUG_WARN(("Unknown type %#x signed 64bit int = %"PRIi64"\n", list->elements[x]->mapi_id,
                             *(int64_t*)list->elements[x]->data));
                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
 
                     } else if (list->elements[x]->type == (uint32_t)0x0007) {
-                        DEBUG_EMAIL(("Unknown type %#x application time [size = %#x]\n", list->elements[x]->mapi_id,
+                        DEBUG_WARN(("Unknown type %#x application time [size = %#x]\n", list->elements[x]->mapi_id,
                             list->elements[x]->size));
                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
 
                     } else if (list->elements[x]->type == (uint32_t)0x000a) {
-                        DEBUG_EMAIL(("Unknown type %#x 32bit error value = %i\n", list->elements[x]->mapi_id,
+                        DEBUG_WARN(("Unknown type %#x 32bit error value = %i\n", list->elements[x]->mapi_id,
                             *(int32_t*)list->elements[x]->data));
 
                     } else if (list->elements[x]->type == (uint32_t)0x000b) {
-                        DEBUG_EMAIL(("Unknown type %#x 16bit boolean = %s [%hi]\n", list->elements[x]->mapi_id,
+                        DEBUG_WARN(("Unknown type %#x 16bit boolean = %s [%hi]\n", list->elements[x]->mapi_id,
                             (*((int16_t*)list->elements[x]->data)!=0?"True":"False"),
                             *((int16_t*)list->elements[x]->data)));
 
                     } else if (list->elements[x]->type == (uint32_t)0x000d) {
-                        DEBUG_EMAIL(("Unknown type %#x Embedded object [size = %#x]\n", list->elements[x]->mapi_id,
+                        DEBUG_WARN(("Unknown type %#x Embedded object [size = %#x]\n", list->elements[x]->mapi_id,
                             list->elements[x]->size));
                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
 
                     } else if (list->elements[x]->type == (uint32_t)0x0014) {
-                        DEBUG_EMAIL(("Unknown type %#x signed 64bit int = %"PRIi64"\n", list->elements[x]->mapi_id,
+                        DEBUG_WARN(("Unknown type %#x signed 64bit int = %"PRIi64"\n", list->elements[x]->mapi_id,
                             *(int64_t*)list->elements[x]->data));
                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
 
                     } else if (list->elements[x]->type == (uint32_t)0x001e) {
-                        DEBUG_EMAIL(("Unknown type %#x String Data = \"%s\"\n", list->elements[x]->mapi_id,
+                        DEBUG_WARN(("Unknown type %#x String Data = \"%s\"\n", list->elements[x]->mapi_id,
                             list->elements[x]->data));
 
                     } else if (list->elements[x]->type == (uint32_t)0x001f) {
-                        DEBUG_EMAIL(("Unknown type %#x Unicode String Data [size = %#x]\n", list->elements[x]->mapi_id,
+                        DEBUG_WARN(("Unknown type %#x Unicode String Data [size = %#x]\n", list->elements[x]->mapi_id,
                             list->elements[x]->size));
                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
 
                     } else if (list->elements[x]->type == (uint32_t)0x0040) {
-                        DEBUG_EMAIL(("Unknown type %#x Date = \"%s\"\n", list->elements[x]->mapi_id,
+                        DEBUG_WARN(("Unknown type %#x Date = \"%s\"\n", list->elements[x]->mapi_id,
                             pst_fileTimeToAscii((FILETIME*)list->elements[x]->data)));
 
                     } else if (list->elements[x]->type == (uint32_t)0x0048) {
-                        DEBUG_EMAIL(("Unknown type %#x OLE GUID [size = %#x]\n", list->elements[x]->mapi_id,
+                        DEBUG_WARN(("Unknown type %#x OLE GUID [size = %#x]\n", list->elements[x]->mapi_id,
                             list->elements[x]->size));
                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
 
                     } else if (list->elements[x]->type == (uint32_t)0x0102) {
-                        DEBUG_EMAIL(("Unknown type %#x Binary Data [size = %#x]\n", list->elements[x]->mapi_id,
+                        DEBUG_WARN(("Unknown type %#x Binary Data [size = %#x]\n", list->elements[x]->mapi_id,
                             list->elements[x]->size));
                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
 
                     } else if (list->elements[x]->type == (uint32_t)0x1003) {
-                        DEBUG_EMAIL(("Unknown type %#x Array of 32 bit values [size = %#x]\n", list->elements[x]->mapi_id,
+                        DEBUG_WARN(("Unknown type %#x Array of 32 bit values [size = %#x]\n", list->elements[x]->mapi_id,
                             list->elements[x]->size));
                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
 
                     } else if (list->elements[x]->type == (uint32_t)0x1014) {
-                        DEBUG_EMAIL(("Unknown type %#x Array of 64 bit values [siize = %#x]\n", list->elements[x]->mapi_id,
+                        DEBUG_WARN(("Unknown type %#x Array of 64 bit values [siize = %#x]\n", list->elements[x]->mapi_id,
                             list->elements[x]->size));
                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
 
                     } else if (list->elements[x]->type == (uint32_t)0x101e) {
-                        DEBUG_EMAIL(("Unknown type %#x Array of Strings [size = %#x]\n", list->elements[x]->mapi_id,
+                        DEBUG_WARN(("Unknown type %#x Array of Strings [size = %#x]\n", list->elements[x]->mapi_id,
                             list->elements[x]->size));
                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
 
                     } else if (list->elements[x]->type == (uint32_t)0x101f) {
-                        DEBUG_EMAIL(("Unknown type %#x Array of Unicode Strings [size = %#x]\n", list->elements[x]->mapi_id,
+                        DEBUG_WARN(("Unknown type %#x Array of Unicode Strings [size = %#x]\n", list->elements[x]->mapi_id,
                             list->elements[x]->size));
                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
 
                     } else if (list->elements[x]->type == (uint32_t)0x1102) {
-                        DEBUG_EMAIL(("Unknown type %#x Array of binary data blobs [size = %#x]\n", list->elements[x]->mapi_id,
+                        DEBUG_WARN(("Unknown type %#x Array of binary data blobs [size = %#x]\n", list->elements[x]->mapi_id,
                             list->elements[x]->size));
                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
 
                     } else {
-                        DEBUG_EMAIL(("Unknown type %#x Not Printable [%#x]\n", list->elements[x]->mapi_id,
+                        DEBUG_WARN(("Unknown type %#x Not Printable [%#x]\n", list->elements[x]->mapi_id,
                             list->elements[x]->type));
                         DEBUG_HEXDUMP(list->elements[x]->data, list->elements[x]->size);
                     }
@@ -3197,7 +3201,7 @@
 
     if (pst_read_block_size(pf, list->offset, list->size, &buf) < list->size) {
         //an error occured in block read
-        WARN(("block read error occured. offset = %#"PRIx64", size = %#"PRIx64"\n", list->offset, list->size));
+        DEBUG_WARN(("block read error occured. offset = %#"PRIx64", size = %#"PRIx64"\n", list->offset, list->size));
         if (buf) free(buf);
         DEBUG_RET();
         return NULL;
@@ -3209,7 +3213,7 @@
     LE16_CPU(block_head.count);
 
     if (block_head.type != (uint16_t)0x0002) { // some sort of constant?
-        WARN(("Unknown constant [%#hx] at start of id2 values [offset %#"PRIx64"].\n", block_head.type, list->offset));
+        DEBUG_WARN(("Unknown constant [%#hx] at start of id2 values [offset %#"PRIx64"].\n", block_head.type, list->offset));
         if (buf) free(buf);
         DEBUG_RET();
         return NULL;
@@ -3740,7 +3744,7 @@
         }
 
     } else {
-        WARN(("Unknown encryption: %i. Cannot decrypt\n", type));
+        DEBUG_WARN(("Unknown encryption: %i. Cannot decrypt\n", type));
         DEBUG_RET();
         return -1;
     }
@@ -4159,7 +4163,7 @@
 }
 
 
-char *pst_rfc2425_datetime_format(FILETIME *ft) {
+char *pst_rfc2425_datetime_format(const FILETIME *ft) {
     static char buffer[30];
     struct tm *stm = NULL;
     DEBUG_ENT("rfc2425_datetime_format");
@@ -4172,7 +4176,7 @@
 }
 
 
-char *pst_rfc2445_datetime_format(FILETIME *ft) {
+char *pst_rfc2445_datetime_format(const FILETIME *ft) {
     static char buffer[30];
     struct tm *stm = NULL;
     DEBUG_ENT("rfc2445_datetime_format");
@@ -4273,7 +4277,7 @@
     size_t rc = pst_vb_8bit2utf8(newer, str->str, strlen(str->str) + 1, charset);
     if (rc == (size_t)-1) {
         free(newer->b);
-        DEBUG_EMAIL(("Failed to convert %s to utf-8 - %s\n", charset, str->str));
+        DEBUG_WARN(("Failed to convert %s to utf-8 - %s\n", charset, str->str));
     }
     else {
         free(str->str);
--- a/src/libpst.h	Fri Apr 17 13:08:31 2009 -0700
+++ b/src/libpst.h	Mon Apr 20 19:39:26 2009 -0700
@@ -843,7 +843,7 @@
  * @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_open(pst_file *pf, const char *name);
 
 
 /** Load the index entries from the pst file. This loads both the
@@ -872,7 +872,7 @@
  * @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);
+pst_desc_tree* pst_getTopOfFolders(pst_file *pf, const pst_item *root);
 
 
 /** Assemble the binary attachment into a single buffer.
@@ -934,7 +934,7 @@
 
 /** 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 buf  pointer to the buffer to be decrypted in place
  * @param size size of the buffer
  * @param type
     @li 0 PST_NO_ENCRYPT, none
@@ -990,14 +990,14 @@
  * @param ft time to be converted
  * @return   time in rfc2425 format
  */
-char *         pst_rfc2425_datetime_format(FILETIME *ft);
+char *         pst_rfc2425_datetime_format(const 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);
+char *         pst_rfc2445_datetime_format(const FILETIME *ft);
 
 
 /** Get the default character set for this item. This is used to find
--- a/src/lspst.c	Fri Apr 17 13:08:31 2009 -0700
+++ b/src/lspst.c	Mon Apr 20 19:39:26 2009 -0700
@@ -234,11 +234,9 @@
         item->file_as.str = strdup(temp);
         item->file_as.is_utf8 = 1;
     }
-    WARN(("item->file_as = '%s'.\n", item->file_as.str));
 
     d_ptr = pst_getTopOfFolders(&pstfile, item);
     if (!d_ptr) DIE(("Top of folders record not found. Cannot continue\n"));
-    DEBUG_MAIN(("d_ptr(TOF) = %p.\n", d_ptr));
 
     process(item, d_ptr->child);    // do the childred of TOPF
     pst_freeItem(item);
--- a/src/pst2dii.cpp.in	Fri Apr 17 13:08:31 2009 -0700
+++ b/src/pst2dii.cpp.in	Mon Apr 20 19:39:26 2009 -0700
@@ -204,11 +204,7 @@
     if (!(fp = fopen(temp, "wb"))) {
         WARN(("write_separate_attachment: Cannot open attachment save file \"%s\"\n", temp));
     } else {
-        if (current_attach->data.data)
-            pst_fwrite(current_attach->data.data, 1, current_attach->data.size, fp);
-        else {
-            (void)pst_attach_to_file(pst, current_attach, fp);
-        }
+        (void)pst_attach_to_file(pst, current_attach, fp);
         fclose(fp);
     }
     string rc(temp);
--- a/src/readpst.c	Fri Apr 17 13:08:31 2009 -0700
+++ b/src/readpst.c	Mon Apr 20 19:39:26 2009 -0700
@@ -786,11 +786,7 @@
     if (!(fp = fopen(temp, "w"))) {
         WARN(("write_separate_attachment: Cannot open attachment save file \"%s\"\n", temp));
     } else {
-        if (attach->data.data)
-            pst_fwrite(attach->data.data, (size_t)1, attach->data.size, fp);
-        else {
-            (void)pst_attach_to_file(pst, attach, fp);
-        }
+        (void)pst_attach_to_file(pst, attach, fp);
         fclose(fp);
     }
     if (temp) free(temp);
@@ -829,18 +825,10 @@
 void write_inline_attachment(FILE* f_output, pst_item_attach* attach, char *boundary, pst_file* pst)
 {
     char *attach_filename;
-    char *enc = NULL; // base64 encoded attachment
     DEBUG_ENT("write_inline_attachment");
     DEBUG_EMAIL(("Attachment Size is %"PRIu64", id %#"PRIx64"\n", (uint64_t)attach->data.size, attach->i_id));
-    if (attach->data.data) {
-        enc = pst_base64_encode (attach->data.data, attach->data.size);
-        if (!enc) {
-            DEBUG_EMAIL(("ERROR base64_encode returned NULL. Must have failed\n"));
-            DEBUG_RET();
-            return;
-        }
-    }
-    else {
+
+    if (!attach->data.data) {
         // make sure we can fetch data from the id
         pst_index_ll *ptr = pst_getID(pst, attach->i_id);
         if (!ptr) {
@@ -867,13 +855,7 @@
         fprintf(f_output, "Content-Disposition: attachment; filename=\"%s\"\n\n", attach_filename);
     }
 
-    if (attach->data.data) {
-        pst_fwrite(enc, 1, strlen(enc), f_output);
-        DEBUG_EMAIL(("Attachment Size after encoding is %i\n", strlen(enc)));
-        free(enc);  // caught by valgrind
-    } else {
-        (void)pst_attach_to_file_base64(pst, attach, f_output);
-    }
+    (void)pst_attach_to_file_base64(pst, attach, f_output);
     fprintf(f_output, "\n\n");
     DEBUG_RET();
 }
--- a/src/vbuf.c	Fri Apr 17 13:08:31 2009 -0700
+++ b/src/vbuf.c	Mon Apr 20 19:39:26 2009 -0700
@@ -51,12 +51,12 @@
         i8totarget = iconv_open(target_charset, "utf-8");
         if (i8totarget == (iconv_t)-1) {
             target_open_from = 0;
-            WARN(("Couldn't open iconv descriptor for utf-8 to %s.\n", target_charset));
+            DEBUG_WARN(("Couldn't open iconv descriptor for utf-8 to %s.\n", target_charset));
         }
         target2i8 = iconv_open("utf-8", target_charset);
         if (target2i8 == (iconv_t)-1) {
             target_open_to = 0;
-            WARN(("Couldn't open iconv descriptor for %s to utf-8.\n", target_charset));
+            DEBUG_WARN(("Couldn't open iconv descriptor for %s to utf-8.\n", target_charset));
         }
     }
 }
@@ -201,8 +201,7 @@
     if (unicode_up) pst_unicode_close();
     i16to8 = iconv_open("utf-8", "utf-16le");
     if (i16to8 == (iconv_t)-1) {
-        WARN(("Couldn't open iconv descriptor for utf-16le to utf-8.\n"));
-        exit(1);
+        DEBUG_WARN(("Couldn't open iconv descriptor for utf-16le to utf-8.\n"));
     }
     unicode_up = 1;
 }
@@ -216,7 +215,7 @@
     char *outbuf        = NULL;
     int   myerrno;
 
-    ASSERT(unicode_up, "vb_utf16to8() called before unicode started.");
+    if (!unicode_up) return (size_t)-1;   // failure to open iconv
     pst_vbresize(dest, iblen);
 
     //Bad Things can happen if a non-zero-terminated utf16 string comes through here