From 82f2bf9ec834ba38800c347ee83120f0da86267e Mon Sep 17 00:00:00 2001 From: Eric Kidd Date: Fri, 9 Jul 2010 10:04:50 -0400 Subject: [PATCH] Compute MAPI PR_ENTRYID for messages and attachments In e-discovery applications, messages will often be referred to by a MAPI PR_ENTRYID. This is a computed property, as described here: http://pstsdk.codeplex.com/Thread/View.aspx?ThreadId=215111 Because this is a fairly useful property, and because it's relatively hard to calculate, I feel it might be worth including somewhere in pstsdk. I wanted to implement a node::get_entry_id function, but because get_entry_id needs access to the message store property bag, this would have made the ndb layer depend on the ltp layer. Thus, this patch provides a property_bag::get_entry_id() function, which does not require any additional dependencies between layers. --- pstsdk/ltp/propbag.h | 25 +++++++++++++++++++++++++ pstsdk/pst/message.h | 10 ++++++++++ test/pstlevel.cpp | 25 +++++++++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/pstsdk/ltp/propbag.h b/pstsdk/ltp/propbag.h index 06cc0a1..9504f03 100644 --- a/pstsdk/ltp/propbag.h +++ b/pstsdk/ltp/propbag.h @@ -79,6 +79,10 @@ class property_bag : public const_property_object //! \returns The node node& get_node() { return m_pbth->get_node(); } + //! \brief Get the MAPI entry id for this node's property bag. + //! \returns The MAPI entry id + std::vector get_entry_id() const; + private: property_bag& operator=(const property_bag& other); // = delete @@ -241,4 +245,25 @@ inline pstsdk::hnid_stream_device pstsdk::property_bag::open_prop_stream(prop_id else return m_pbth->get_heap_ptr()->open_stream(h_id); } + +inline std::vector pstsdk::property_bag::get_entry_id() const { + using namespace std; + + // A MAPI entry id contains 4 leading 0 bytes, the data store ID, and + // the node ID. + vector entry_id(4, 0); + + node store(get_node().get_db()->lookup_node(nid_message_store)); + property_bag store_props(store); + vector store_id(store_props.read_prop >(0x0ff9)); + copy(store_id.begin(), store_id.end(), + insert_iterator >(entry_id, entry_id.end())); + + node_id nid(get_node().get_id()); + for (int i = sizeof(node_id) - 1; i >= 0; --i) + entry_id.push_back((nid >> 8*i) & 0xff); + + return entry_id; +} + #endif diff --git a/pstsdk/pst/message.h b/pstsdk/pst/message.h index 5a4091a..8d4810f 100644 --- a/pstsdk/pst/message.h +++ b/pstsdk/pst/message.h @@ -91,6 +91,11 @@ class attachment const property_bag& get_property_bag() const { return m_bag; } + //! \brief Get the MAPI entry ID of this attachment + //! \returns The MAPI entry ID of this attachment + std::vector get_entry_id() const + { return m_bag.get_entry_id(); } + private: attachment& operator=(const attachment&); // = delete friend class message; @@ -346,6 +351,11 @@ class message node_id get_id() const { return m_bag.get_node().get_id(); } + //! \brief Get the MAPI entry ID of this message + //! \returns The MAPI entry ID of this message + std::vector get_entry_id() const + { return m_bag.get_entry_id(); } + private: message& operator=(const message&); // = delete diff --git a/test/pstlevel.cpp b/test/pstlevel.cpp index 3efa8f8..2ba158c 100644 --- a/test/pstlevel.cpp +++ b/test/pstlevel.cpp @@ -89,6 +89,28 @@ void process_pst(const pstsdk::pst& p) process_folder(root); } +void test_entry_id(pstsdk::pst& p) { + using namespace std; + using namespace pstsdk; + + message m(*p.message_begin()); + attachment a(*m.attachment_begin()); + + const byte expected1_bytes[24] = { + 0x00, 0x00, 0x00, 0x00, 0x6a, 0x55, 0x2b, 0x81, 0x3c, 0x43, 0xf9, 0x43, + 0x84, 0xf1, 0x8b, 0x7d, 0xa2, 0x39, 0x3e, 0x95, 0x00, 0x20, 0x00, 0x24 + }; + vector expected1(expected1_bytes, expected1_bytes + 24); + assert(expected1 == m.get_entry_id()); + + const byte expected2_bytes[24] = { + 0x00, 0x00, 0x00, 0x00, 0x6a, 0x55, 0x2b, 0x81, 0x3c, 0x43, 0xf9, 0x43, + 0x84, 0xf1, 0x8b, 0x7d, 0xa2, 0x39, 0x3e, 0x95, 0x00, 0x00, 0x80, 0x25 + }; + vector expected2(expected2_bytes, expected2_bytes + 24); + assert(expected2 == a.get_entry_id()); +} + void test_pstlevel() { using namespace pstsdk; @@ -107,4 +129,7 @@ void test_pstlevel() // make sure searching by name works process_folder(uni.open_folder(L"Folder")); + + // make sure we can calculate entry_id values + test_entry_id(s1); }