comparison python/python-libpst.cpp @ 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
children ffd1503a7530
comparison
equal deleted inserted replaced
194:885b47107036 195:320cfcba8058
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4
5 #include <iostream>
6 #include <boost/python.hpp>
7 #include <iostream>
8
9 extern "C" {
10 #include "libpst.h"
11 #include "timeconv.h"
12 #include "libstrfunc.h"
13 #include "vbuf.h"
14 #include "lzfu.h"
15 }
16
17 using namespace std;
18 using namespace boost::python;
19
20
21 /** python version of pst_binary, where python is
22 responsible for freeing the underlying buffer */
23 struct ppst_binary : public pst_binary
24 {
25 };
26
27 class pst {
28 public:
29 pst(const string filename);
30 virtual ~pst();
31 pst_desc_tree* pst_getTopOfFolders();
32 ppst_binary pst_attach_to_mem(pst_item_attach *attach);
33 size_t pst_attach_to_file(pst_item_attach *attach, FILE* fp);
34 size_t pst_attach_to_file_base64(pst_item_attach *attach, FILE* fp);
35 pst_desc_tree* pst_getNextDptr(pst_desc_tree* d);
36 pst_item* pst_parse_item(pst_desc_tree *d_ptr, pst_id2_tree *m_head);
37 void pst_freeItem(pst_item *item);
38 pst_index_ll* pst_getID(uint64_t i_id);
39 int pst_decrypt(uint64_t i_id, char *buf, size_t size, unsigned char type);
40 size_t pst_ff_getIDblock_dec(uint64_t i_id, char **buf);
41 size_t pst_ff_getIDblock(uint64_t i_id, char** buf);
42 string pst_rfc2426_escape(char *str);
43 string pst_rfc2425_datetime_format(const FILETIME *ft);
44 string pst_rfc2445_datetime_format(const FILETIME *ft);
45 string pst_default_charset(pst_item *item);
46 void pst_convert_utf8_null(pst_item *item, pst_string *str);
47 void pst_convert_utf8(pst_item *item, pst_string *str);
48
49 private:
50 bool is_open;
51 pst_file pf;
52 pst_item* root;
53 pst_desc_tree* topf;
54
55 };
56
57
58 pst::pst(const string filename) {
59 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
60 is_open = (::pst_open(&pf, f) == 0);
61 root = NULL;
62 topf = NULL;
63 if (is_open) {
64 ::pst_load_index(&pf);
65 ::pst_load_extended_attributes(&pf);
66 root = ::pst_parse_item(&pf, pf.d_head, NULL);
67 topf = ::pst_getTopOfFolders(&pf, root)->child;
68 }
69 }
70
71 pst::~pst() {
72 if (root) pst_freeItem(root);
73 if (is_open) ::pst_close(&pf);
74 }
75
76 pst_desc_tree* pst::pst_getTopOfFolders() {
77 return topf;
78 }
79
80 ppst_binary pst::pst_attach_to_mem(pst_item_attach *attach) {
81 ppst_binary rc;
82 rc.size = rc.size = ::pst_attach_to_mem(&pf, attach, &rc.data);
83 return rc;
84 }
85
86 size_t pst::pst_attach_to_file(pst_item_attach *attach, FILE* fp) {
87 return ::pst_attach_to_file(&pf, attach, fp);
88 }
89
90 size_t pst::pst_attach_to_file_base64(pst_item_attach *attach, FILE* fp) {
91 return ::pst_attach_to_file_base64(&pf, attach, fp);
92 }
93
94 pst_desc_tree* pst::pst_getNextDptr(pst_desc_tree* d) {
95 return ::pst_getNextDptr(d);
96 }
97
98 pst_item* pst::pst_parse_item (pst_desc_tree *d_ptr, pst_id2_tree *m_head) {
99 return ::pst_parse_item(&pf, d_ptr, m_head);
100 }
101
102 void pst::pst_freeItem(pst_item *item) {
103 return ::pst_freeItem(item);
104 }
105
106 pst_index_ll* pst::pst_getID(uint64_t i_id) {
107 return ::pst_getID(&pf, i_id);
108 }
109
110 int pst::pst_decrypt(uint64_t i_id, char *buf, size_t size, unsigned char type) {
111 return ::pst_decrypt(i_id, buf, size, type);
112 }
113
114 size_t pst::pst_ff_getIDblock_dec(uint64_t i_id, char **buf) {
115 return ::pst_ff_getIDblock_dec(&pf, i_id, buf);
116 }
117
118 size_t pst::pst_ff_getIDblock(uint64_t i_id, char** buf) {
119 return ::pst_ff_getIDblock(&pf, i_id, buf);
120 }
121
122 string pst::pst_rfc2426_escape(char *str) {
123 return ::pst_rfc2426_escape(str);
124 }
125
126 string pst::pst_rfc2425_datetime_format(const FILETIME *ft) {
127 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
128 }
129
130 string pst::pst_rfc2445_datetime_format(const FILETIME *ft) {
131 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
132 }
133
134 string pst::pst_default_charset(pst_item *item) {
135 return ::pst_default_charset(item);
136 }
137
138 void pst::pst_convert_utf8_null(pst_item *item, pst_string *str) {
139 ::pst_convert_utf8_null(item, str);
140 }
141
142 void pst::pst_convert_utf8(pst_item *item, pst_string *str) {
143 ::pst_convert_utf8(item, str);
144 }
145
146 struct make_python_string {
147 /* we make no distinction between empty and null strings */
148 static PyObject* convert(char* const &s) {
149 string ss;
150 if (s) ss = string(s);
151 return boost::python::incref(boost::python::object(ss).ptr());
152 }
153 };
154
155 struct make_python_pst_binary {
156 static PyObject* convert(pst_binary const &s) {
157 if (s.data) {
158 string ss;
159 ss = string(s.data, s.size);
160 return boost::python::incref(boost::python::object(ss).ptr());
161 }
162 return NULL;
163 }
164 };
165
166 struct make_python_ppst_binary {
167 static PyObject* convert(ppst_binary const &s) {
168 if (s.data) {
169 string ss;
170 ss = string(s.data, s.size);
171 free(s.data);
172 return boost::python::incref(boost::python::object(ss).ptr());
173 }
174 return NULL;
175 }
176 };
177
178 struct make_python_pst_item_email {
179 static PyObject* convert(pst_item_email* const &s) {
180 if (s) return to_python_indirect<pst_item_email*, detail::make_reference_holder>()(s);
181 return NULL;
182 }
183 };
184
185 struct make_python_pst_item_attach {
186 static PyObject* convert(pst_item_attach* const &s) {
187 if (s) return to_python_indirect<pst_item_attach*, detail::make_reference_holder>()(s);
188 return NULL;
189 }
190 };
191
192 struct make_python_pst_desc_tree {
193 static PyObject* convert(pst_desc_tree* const &s) {
194 if (s) return to_python_indirect<pst_desc_tree*, detail::make_reference_holder>()(s);
195 return NULL;
196 }
197 };
198
199 struct make_python_pst_index_ll {
200 static PyObject* convert(pst_index_ll* const &s) {
201 if (s) return to_python_indirect<pst_index_ll*, detail::make_reference_holder>()(s);
202 return NULL;
203 }
204 };
205
206 BOOST_PYTHON_MODULE(_libpst)
207 {
208 to_python_converter<pst_binary, make_python_pst_binary>();
209 to_python_converter<ppst_binary, make_python_ppst_binary>();
210 to_python_converter<char*, make_python_string>();
211 to_python_converter<pst_item_email*, make_python_pst_item_email>();
212 to_python_converter<pst_item_attach*, make_python_pst_item_attach>();
213 to_python_converter<pst_desc_tree*, make_python_pst_desc_tree>();
214 to_python_converter<pst_index_ll*, make_python_pst_index_ll>();
215
216 class_<FILETIME>("FILETIME")
217 .def_readonly("dwLowDateTime", &FILETIME::dwLowDateTime)
218 .def_readonly("dwHighDateTime", &FILETIME::dwHighDateTime)
219 ;
220
221 class_<pst_entryid>("pst_entryid")
222 .def_readonly("u1", &pst_entryid::u1)
223 .def_readonly("entryid", &pst_entryid::entryid)
224 .def_readonly("id", &pst_entryid::id)
225 ;
226
227 class_<pst_index_ll>("pst_index_ll")
228 .def_readonly("i_id", &pst_index_ll::i_id)
229 .def_readonly("offset", &pst_index_ll::offset)
230 .def_readonly("size", &pst_index_ll::size)
231 .def_readonly("u1", &pst_index_ll::u1)
232 .add_property("next", make_getter(&pst_index_ll::next, return_value_policy<reference_existing_object>()))
233 ;
234
235 class_<pst_id2_tree>("pst_id2_tree")
236 .def_readonly("id2", &pst_id2_tree::id2)
237 .add_property("id", make_getter(&pst_id2_tree::id, return_value_policy<reference_existing_object>()))
238 .add_property("child", make_getter(&pst_id2_tree::child, return_value_policy<reference_existing_object>()))
239 .add_property("next", make_getter(&pst_id2_tree::next, return_value_policy<reference_existing_object>()))
240 ;
241
242 class_<pst_desc_tree>("pst_desc_tree")
243 .def_readonly("d_id", &pst_desc_tree::d_id)
244 .def_readonly("parent_d_id", &pst_desc_tree::parent_d_id)
245 .add_property("desc", make_getter(&pst_desc_tree::desc, return_value_policy<reference_existing_object>()))
246 .add_property("assoc_tree", make_getter(&pst_desc_tree::assoc_tree, return_value_policy<reference_existing_object>()))
247 .def_readonly("no_child", &pst_desc_tree::no_child)
248 .add_property("prev", make_getter(&pst_desc_tree::prev, return_value_policy<reference_existing_object>()))
249 .add_property("next", make_getter(&pst_desc_tree::next, return_value_policy<reference_existing_object>()))
250 .add_property("parent", make_getter(&pst_desc_tree::parent, return_value_policy<reference_existing_object>()))
251 .add_property("child", make_getter(&pst_desc_tree::child, return_value_policy<reference_existing_object>()))
252 .add_property("child_tail", make_getter(&pst_desc_tree::child_tail, return_value_policy<reference_existing_object>()))
253 ;
254
255 class_<pst_string>("pst_string")
256 .def_readonly("is_utf8", &pst_string::is_utf8)
257 .def_readonly("str", &pst_string::str)
258 ;
259
260 class_<pst_item_email>("pst_item_email")
261 .add_property("arrival_date", make_getter(&pst_item_email::arrival_date, return_value_policy<reference_existing_object>()))
262 .def_readonly("autoforward", &pst_item_email::autoforward)
263 .def_readonly("cc_address", &pst_item_email::cc_address)
264 .def_readonly("bcc_address", &pst_item_email::bcc_address)
265 .def_readonly("conversation_index", &pst_item_email::conversation_index)
266 .def_readonly("conversion_prohibited", &pst_item_email::conversion_prohibited)
267 .def_readonly("delete_after_submit", &pst_item_email::delete_after_submit)
268 .def_readonly("delivery_report", &pst_item_email::delivery_report)
269 .def_readonly("encrypted_body", &pst_item_email::encrypted_body)
270 .def_readonly("encrypted_htmlbody", &pst_item_email::encrypted_htmlbody)
271 .def_readonly("header", &pst_item_email::header)
272 .def_readonly("htmlbody", &pst_item_email::htmlbody)
273 .def_readonly("importance", &pst_item_email::importance)
274 .def_readonly("in_reply_to", &pst_item_email::in_reply_to)
275 .def_readonly("message_cc_me", &pst_item_email::message_cc_me)
276 .def_readonly("message_recip_me", &pst_item_email::message_recip_me)
277 .def_readonly("message_to_me", &pst_item_email::message_to_me)
278 .def_readonly("messageid", &pst_item_email::messageid)
279 .def_readonly("original_sensitivity", &pst_item_email::original_sensitivity)
280 .def_readonly("original_bcc", &pst_item_email::original_bcc)
281 .def_readonly("original_cc", &pst_item_email::original_cc)
282 .def_readonly("original_to", &pst_item_email::original_to)
283 ;
284
285 class_<pst_item_folder>("pst_item_folder")
286 .def_readonly("item_count", &pst_item_folder::item_count)
287 ;
288
289 class_<pst_item_message_store>("pst_item_message_store")
290 .add_property("top_of_personal_folder", make_getter(&pst_item_message_store::top_of_personal_folder, return_value_policy<reference_existing_object>()))
291 ;
292
293 class_<pst_item_contact>("pst_item_contact")
294 .def_readonly("account_name", &pst_item_contact::account_name)
295 ;
296
297 class_<pst_item_attach>("pst_item_attach")
298 .def_readonly("filename1", &pst_item_attach::filename1)
299 .def_readonly("filename2", &pst_item_attach::filename2)
300 .def_readonly("mimetype", &pst_item_attach::mimetype)
301 .def_readonly("data", &pst_item_attach::data)
302 .def_readonly("id2_val", &pst_item_attach::id2_val)
303 .def_readonly("i_id", &pst_item_attach::i_id)
304 .add_property("id2_head", make_getter(&pst_item_attach::id2_head, return_value_policy<reference_existing_object>()))
305 .def_readonly("method", &pst_item_attach::method)
306 .def_readonly("position", &pst_item_attach::position)
307 .def_readonly("sequence", &pst_item_attach::sequence)
308 .add_property("next", make_getter(&pst_item_attach::next, return_value_policy<reference_existing_object>()))
309 ;
310
311 class_<pst_item_extra_field>("pst_item_extra_field")
312 .def_readonly("field_name", &pst_item_extra_field::field_name)
313 ;
314
315 class_<pst_item_journal>("pst_item_journal")
316 .def_readonly("description", &pst_item_journal::description)
317 ;
318
319 class_<pst_item_appointment>("pst_item_appointment")
320 .add_property("end", make_getter(&pst_item_appointment::end, return_value_policy<reference_existing_object>()))
321 .def_readonly("label", &pst_item_appointment::label)
322 ;
323
324 class_<pst_item>("pst_item")
325 .add_property("email", make_getter(&pst_item::email, return_value_policy<reference_existing_object>()))
326 .add_property("folder", make_getter(&pst_item::folder, return_value_policy<reference_existing_object>()))
327 .add_property("contact", make_getter(&pst_item::contact, return_value_policy<reference_existing_object>()))
328 .add_property("attach", make_getter(&pst_item::attach, return_value_policy<reference_existing_object>()))
329 .add_property("message_store", make_getter(&pst_item::message_store, return_value_policy<reference_existing_object>()))
330 .add_property("extra_fields", make_getter(&pst_item::extra_fields, return_value_policy<reference_existing_object>()))
331 .add_property("journal", make_getter(&pst_item::journal, return_value_policy<reference_existing_object>()))
332 .add_property("appointment", make_getter(&pst_item::appointment, return_value_policy<reference_existing_object>()))
333 .def_readonly("type", &pst_item::type)
334 .def_readonly("ascii_type", &pst_item::ascii_type)
335 .def_readonly("flags", &pst_item::flags)
336 .def_readonly("file_as", &pst_item::file_as)
337 .def_readonly("comment", &pst_item::comment)
338 .def_readonly("body_charset", &pst_item::body_charset)
339 .def_readonly("body", &pst_item::body)
340 .def_readonly("subject", &pst_item::subject)
341 .def_readonly("internet_cpid", &pst_item::internet_cpid)
342 .def_readonly("message_codepage", &pst_item::message_codepage)
343 .def_readonly("message_size", &pst_item::message_size)
344 .def_readonly("outlook_version", &pst_item::outlook_version)
345 .def_readonly("record_key", &pst_item::record_key)
346 .def_readonly("predecessor_change", &pst_item::predecessor_change)
347 .def_readonly("response_requested", &pst_item::response_requested)
348 .add_property("create_date", make_getter(&pst_item::create_date, return_value_policy<reference_existing_object>()))
349 .add_property("modify_date", make_getter(&pst_item::modify_date, return_value_policy<reference_existing_object>()))
350 .def_readonly("private_member", &pst_item::private_member)
351 ;
352
353 class_<pst_x_attrib_ll>("pst_x_attrib_ll")
354 .def_readonly("mytype", &pst_x_attrib_ll::mytype)
355 .def_readonly("map", &pst_x_attrib_ll::map)
356 .def_readonly("data", &pst_x_attrib_ll::data)
357 .def_readonly("next", &pst_x_attrib_ll::next)
358 ;
359
360 class_<pst_file>("pst_file")
361 .add_property("i_head", make_getter(&pst_file::i_head, return_value_policy<reference_existing_object>()))
362 .add_property("i_tail", make_getter(&pst_file::i_tail, return_value_policy<reference_existing_object>()))
363 .add_property("d_head", make_getter(&pst_file::d_head, return_value_policy<reference_existing_object>()))
364 .add_property("d_tail", make_getter(&pst_file::d_tail, return_value_policy<reference_existing_object>()))
365 .def_readonly("do_read64", &pst_file::do_read64)
366 .def_readonly("index1", &pst_file::index1)
367 .def_readonly("index1_back", &pst_file::index1_back)
368 .def_readonly("index2", &pst_file::index2)
369 .def_readonly("index2_back", &pst_file::index2_back)
370 .def_readonly("size", &pst_file::size)
371 .def_readonly("encryption", &pst_file::encryption)
372 .def_readonly("ind_type", &pst_file::ind_type)
373 ;
374
375 class_<pst>("pst", init<string>())
376 .def("pst_getTopOfFolders", &pst::pst_getTopOfFolders, return_value_policy<reference_existing_object>())
377 .def("pst_attach_to_mem", &pst::pst_attach_to_mem)
378 .def("pst_attach_to_file", &pst::pst_attach_to_file)
379 .def("pst_attach_to_file_base64", &pst::pst_attach_to_file_base64)
380 .def("pst_getNextDptr", &pst::pst_getNextDptr, return_value_policy<reference_existing_object>())
381 .def("pst_parse_item", &pst::pst_parse_item, return_value_policy<reference_existing_object>())
382 .def("pst_freeItem", &pst::pst_freeItem)
383 .def("pst_getID", &pst::pst_getID, return_value_policy<reference_existing_object>())
384 .def("pst_decrypt", &pst::pst_decrypt)
385 .def("pst_ff_getIDblock_dec", &pst::pst_ff_getIDblock_dec)
386 .def("pst_ff_getIDblock", &pst::pst_ff_getIDblock)
387 .def("pst_rfc2426_escape", &pst::pst_rfc2426_escape)
388 .def("pst_rfc2425_datetime_format", &pst::pst_rfc2425_datetime_format)
389 .def("pst_rfc2445_datetime_format", &pst::pst_rfc2445_datetime_format)
390 .def("pst_default_charset", &pst::pst_default_charset)
391 .def("pst_convert_utf8_null", &pst::pst_convert_utf8_null)
392 .def("pst_convert_utf8", &pst::pst_convert_utf8)
393 ;
394 }
395
396