Fairport  v1.0.38
fairport/pst/message.h
Go to the documentation of this file.
00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 #ifndef FAIRPORT_PST_MESSAGE_H
00009 #define FAIRPORT_PST_MESSAGE_H
00010 
00011 #include <functional>
00012 #include <ostream>
00013 #include <boost/iterator/transform_iterator.hpp>
00014 
00015 #include "fairport/ndb/database_iface.h"
00016 #include "fairport/ndb/node.h"
00017 
00018 #include "fairport/ltp/propbag.h"
00019 #include "fairport/ltp/table.h"
00020 
00021 #include "fairport/pst/pstutil.h"
00022 
00023 namespace fairport
00024 {
00025 
00028 
00029 class message;
00030 class contact;
00037 class attachment
00038 {
00039 public:
00040     // property access
00045     std::wstring get_filename() const;
00052     std::vector<byte> get_bytes() const
00053         { return m_bag.read_prop<std::vector<byte> >(0x3701); }
00064     hnid_stream_device open_byte_stream()
00065         { return m_bag.open_prop_stream(0x3701); }
00073     size_t size() const
00074         { return m_bag.read_prop<uint>(0xe20); }
00079     size_t content_size() const
00080         { return m_bag.size(0x3701); }
00087     bool is_message() const
00088         { return m_bag.read_prop<uint>(0x3705) == 5; }
00092     message open_as_message() const;
00093 
00094     // lower layer access
00097     property_bag& get_property_bag()
00098         { return m_bag; }
00100     const property_bag& get_property_bag() const
00101         { return m_bag; }
00102 
00103 private:
00104     attachment& operator=(const attachment&); // = delete
00105     friend class message;
00106     friend class contact;
00107     friend class attachment_transform;
00108 
00109     explicit attachment(const property_bag& attachment)
00110         : m_bag(attachment) { }
00111 
00112     property_bag m_bag;
00113 };
00114 
00120 inline std::ostream& operator<<(std::ostream& out, const attachment& attach)
00121 {
00122     std::vector<byte> data = attach.get_bytes();
00123     out.write(reinterpret_cast<char*>(&data[0]), data.size());
00124     return out;
00125 }
00126 
00131 class attachment_transform : public std::unary_function<const_table_row, attachment>
00132 {
00133 public:
00136     explicit attachment_transform(const node& n) 
00137         : m_node(n) { }
00138 
00142     attachment operator()(const const_table_row& row) const
00143         { return attachment(property_bag(m_node.lookup(row.get_row_id()))); }
00144 
00145 private:
00146     node m_node;
00147 };
00148 
00153 class recipient
00154 {
00155 public:
00156     // property access
00160     std::wstring get_name() const
00161         { return m_row.read_prop<std::wstring>(0x3001); }
00165     recipient_type get_type() const
00166         { return static_cast<recipient_type>(m_row.read_prop<ulong>(0xc15)); }
00170     std::wstring get_address_type() const
00171         { return m_row.read_prop<std::wstring>(0x3002); }
00175     std::wstring get_email_address() const
00176         { return m_row.read_prop<std::wstring>(0x39fe); }
00179     bool has_email_address() const
00180         { return m_row.prop_exists(0x39fe); }
00184     std::wstring get_account_name() const
00185         { return m_row.read_prop<std::wstring>(0x3a00); }
00188     bool has_account_name() const
00189         { return m_row.prop_exists(0x3a00); }
00190 
00191     // lower layer access
00194     const_table_row& get_property_row()
00195         { return m_row; }
00197     const const_table_row& get_property_row() const
00198         { return m_row; }
00199 
00200 private:
00201     recipient& operator=(const recipient&); // = delete
00202     friend struct recipient_transform;
00203 
00204     explicit recipient(const const_table_row& row)
00205         : m_row(row) { }
00206     const_table_row m_row;
00207 };
00208 
00213 struct recipient_transform : public std::unary_function<const_table_row, recipient>
00214 {
00215     recipient operator()(const_table_row row) const
00216         { return recipient(row); }
00217 };
00218 
00229 class message : public detail::itembase
00230 {
00231 public:
00233     typedef boost::transform_iterator<attachment_transform, const_table_row_iter> attachment_iterator;
00235     typedef boost::transform_iterator<recipient_transform, const_table_row_iter> recipient_iterator;
00236 
00239     explicit message(const node& n)
00240         : detail::itembase(n) { }
00241     message(const message& other);
00242 
00243     // subobject discovery/enumeration
00246     attachment_iterator attachment_begin() const
00247         { return boost::make_transform_iterator(get_attachment_table().begin(), attachment_transform(get_property_bag().get_node())); }
00250     attachment_iterator attachment_end() const
00251         { return boost::make_transform_iterator(get_attachment_table().end(), attachment_transform(get_property_bag().get_node())); }
00254     recipient_iterator recipient_begin() const
00255         { return boost::make_transform_iterator(get_recipient_table().begin(), recipient_transform()); }
00258     recipient_iterator recipient_end() const
00259         { return boost::make_transform_iterator(get_recipient_table().end(), recipient_transform()); }
00260 
00261     // property access
00265     std::wstring get_subject() const;
00268     bool has_subject() const
00269         { return get_property_bag().prop_exists(0x37); }
00273     std::wstring get_body() const
00274         { return get_property_bag().read_prop<std::wstring>(0x1000); }
00285     hnid_stream_device open_body_stream()
00286         { return get_property_bag().open_prop_stream(0x1000); }
00289     size_t body_size() const
00290         { return get_property_bag().size(0x1000); }
00293     bool has_body() const
00294         { return get_property_bag().prop_exists(0x1000); }
00298     std::wstring get_html_body() const
00299         { return get_property_bag().read_prop<std::wstring>(0x1013); }
00310     hnid_stream_device open_html_body_stream()
00311         { return get_property_bag().open_prop_stream(0x1013); }
00314     size_t html_body_size() const
00315         { return get_property_bag().size(0x1013); }
00318     bool has_html_body() const
00319         { return get_property_bag().prop_exists(0x1013); }
00320     // \brief Get the total size of this message
00323     size_t size() const
00324         { return get_property_bag().read_prop<slong>(0xe08); }
00327     size_t get_attachment_count() const
00328         { return get_attachment_table().size(); }
00332     boost::posix_time::ptime get_delivery_time() const
00333         { return get_property_bag().read_prop<boost::posix_time::ptime>(0x0e06); }
00337     boost::posix_time::ptime get_last_modification_time() const
00338         { return get_property_bag().read_prop<boost::posix_time::ptime>(0x3008); }
00339 
00342     size_t get_recipient_count() const
00343         { return get_recipient_table().size(); }
00344 
00345     // lower layer access
00348     table& get_attachment_table()
00349         { return const_cast<table&>(const_cast<const message*>(this)->get_attachment_table()); }
00352     table& get_recipient_table()
00353         { return const_cast<table&>(const_cast<const message*>(this)->get_recipient_table()); }
00355     const table& get_attachment_table() const;
00357     const table& get_recipient_table() const;
00358 
00359 private:
00360     mutable std::tr1::shared_ptr<table> m_attachment_table;
00361     mutable std::tr1::shared_ptr<table> m_recipient_table;
00362 };
00363 
00364 typedef detail::item_transform_row<message> message_transform_row;
00365 typedef detail::item_transform_info<message> message_transform_info;
00366 } // end namespace fairport
00367 
00368 inline std::wstring fairport::attachment::get_filename() const
00369 {
00370     try
00371     {
00372         return m_bag.read_prop<std::wstring>(0x3707);
00373     } 
00374     catch(key_not_found<prop_id>&)
00375     {
00376         return m_bag.read_prop<std::wstring>(0x3704);
00377     }
00378 }
00379 
00380 inline fairport::message fairport::attachment::open_as_message() const
00381 {
00382     if(!is_message()) 
00383         throw std::bad_cast();
00384 
00385     std::vector<byte> buffer = get_bytes();
00386     disk::sub_object* psubo = (disk::sub_object*)&buffer[0];
00387 
00388     return message(m_bag.get_node().lookup(psubo->nid));
00389 }
00390 
00391 inline fairport::message::message(const fairport::message& other)
00392 : detail::itembase(other)
00393 {
00394     if(other.m_attachment_table)
00395         m_attachment_table.reset(new table(*other.m_attachment_table));
00396     if(other.m_recipient_table)
00397         m_recipient_table.reset(new table(*other.m_recipient_table));
00398 }
00399 
00400 inline const fairport::table& fairport::message::get_attachment_table() const
00401 {
00402     if(!m_attachment_table)
00403     {
00404         try
00405         {
00406             m_attachment_table.reset(new table(get_property_bag().get_node().lookup(nid_attachment_table)));
00407         }
00408         catch (const key_not_found<node_id>&) 
00409         {
00410             m_attachment_table.reset(new table());
00411         }
00412     }
00413 
00414     return *m_attachment_table;
00415 }
00416 
00417 inline const fairport::table& fairport::message::get_recipient_table() const
00418 {
00419     if(!m_recipient_table)
00420     {
00421         try
00422         {
00423             m_recipient_table.reset(new table(get_property_bag().get_node().lookup(nid_recipient_table)));
00424         }
00425         catch (const key_not_found<node_id>&)
00426         {
00427             m_recipient_table.reset(new table());
00428         }
00429     }
00430 
00431     return *m_recipient_table;
00432 }
00433 
00434 inline std::wstring fairport::message::get_subject() const
00435 {
00436     std::wstring buffer = get_property_bag().read_prop<std::wstring>(0x37);
00437 
00438     if(buffer.size() && buffer[0] == message_subject_prefix_lead_byte)
00439     {
00440         // Skip the second chracter as well
00441         return buffer.substr(2);
00442     }
00443     else
00444     {
00445         return buffer;
00446     }
00447 }
00448 #endif