00001 extern "C" {
00002 #include "define.h"
00003 #include "msg.h"
00004 #include <gsf/gsf-utils.h>
00005
00006 #include <gsf/gsf-input-stdio.h>
00007 #include <gsf/gsf-infile.h>
00008 #include <gsf/gsf-infile-stdio.h>
00009
00010 #include <gsf/gsf-output-stdio.h>
00011 #include <gsf/gsf-outfile.h>
00012 #include <gsf/gsf-outfile-msole.h>
00013 }
00014
00015 #include <list>
00016 #include <vector>
00017 #include <string>
00018
00019 using namespace std;
00020
00021 struct property {
00022 uint32_t tag;
00023 uint32_t flags;
00024 uint32_t length;
00025 uint32_t reserved;
00026 };
00027 typedef list<property> property_list;
00028
00029
00035 static void convert_8bit(pst_string &str, const char *charset);
00036 static void convert_8bit(pst_string &str, const char *charset) {
00037 if (!str.str) return;
00038 if (!str.is_utf8) return;
00039
00040 DEBUG_ENT("convert_8bit");
00041 pst_vbuf *newer = pst_vballoc(2);
00042 size_t strsize = strlen(str.str);
00043 size_t rc = pst_vb_utf8to8bit(newer, str.str, strsize, charset);
00044 if (rc == (size_t)-1) {
00045
00046 free(newer->b);
00047 DEBUG_INFO(("Failed to convert utf-8 to %s\n", charset));
00048 DEBUG_HEXDUMPC(str.str, strsize, 0x10);
00049 }
00050 else {
00051
00052 pst_vbgrow(newer, 1);
00053 newer->b[newer->dlen] = '\0';
00054 free(str.str);
00055 str.str = newer->b;
00056 }
00057 free(newer);
00058 DEBUG_RET();
00059 }
00060
00061
00062 static void empty_property(GsfOutfile *out, uint32_t tag);
00063 static void empty_property(GsfOutfile *out, uint32_t tag) {
00064 vector<char> n(50);
00065 snprintf(&n[0], n.size(), "__substg1.0_%08X", tag);
00066 GsfOutput* dst = gsf_outfile_new_child(out, &n[0], false);
00067 gsf_output_close(dst);
00068 g_object_unref(G_OBJECT(dst));
00069 }
00070
00071
00072 static void string_property(GsfOutfile *out, property_list &prop, uint32_t tag, const char *contents, size_t size);
00073 static void string_property(GsfOutfile *out, property_list &prop, uint32_t tag, const char *contents, size_t size) {
00074 if (!contents) return;
00075 size_t term = ((tag & 0x0000ffff) == 0x001e) ? 1 :
00076 ((tag & 0x0000ffff) == 0x001f) ? 2 : 0;
00077 vector<char> n(50);
00078 snprintf(&n[0], n.size(), "__substg1.0_%08X", tag);
00079 GsfOutput* dst = gsf_outfile_new_child(out, &n[0], false);
00080 gsf_output_write(dst, size, (const guint8*)contents);
00081 if (term) {
00082 memset(&n[0], 0, term);
00083 gsf_output_write(dst, term, (const guint8*)&n[0]);
00084 size += term;
00085 }
00086 gsf_output_close(dst);
00087 g_object_unref(G_OBJECT(dst));
00088
00089 property p;
00090 p.tag = tag;
00091 p.flags = 0x6;
00092 p.length = size;
00093 p.reserved = 0;
00094 prop.push_back(p);
00095 }
00096
00097
00098 static void string_property(GsfOutfile *out, property_list &prop, uint32_t tag, FILE *fp);
00099 static void string_property(GsfOutfile *out, property_list &prop, uint32_t tag, FILE *fp) {
00100 vector<char> n(50);
00101 snprintf(&n[0], n.size(), "__substg1.0_%08X", tag);
00102 GsfOutput* dst = gsf_outfile_new_child(out, &n[0], false);
00103
00104 size_t size = 0;
00105 const size_t bsize = 10000;
00106 char buf[bsize];
00107
00108 while (1) {
00109 size_t s = fread(buf, 1, bsize, fp);
00110 if (!s) break;
00111 gsf_output_write(dst, s, (const guint8*)buf);
00112 }
00113
00114 gsf_output_close(dst);
00115 g_object_unref(G_OBJECT(dst));
00116
00117 property p;
00118 p.tag = tag;
00119 p.flags = 0x6;
00120 p.length = size;
00121 p.reserved = 0;
00122 prop.push_back(p);
00123 }
00124
00125
00126 static void string_property(GsfOutfile *out, property_list &prop, uint32_t tag, const char* charset, pst_string &contents);
00127 static void string_property(GsfOutfile *out, property_list &prop, uint32_t tag, const char* charset, pst_string &contents) {
00128 if (contents.str) {
00129 convert_8bit(contents, charset);
00130 string_property(out, prop, tag, contents.str, strlen(contents.str));
00131 }
00132 }
00133
00134
00135 static void strin0_property(GsfOutfile *out, property_list &prop, uint32_t tag, const char* charset, pst_string &contents);
00136 static void strin0_property(GsfOutfile *out, property_list &prop, uint32_t tag, const char* charset, pst_string &contents) {
00137 if (contents.str) {
00138 convert_8bit(contents, charset);
00139 string_property(out, prop, tag, contents.str, strlen(contents.str)+1);
00140 }
00141 }
00142
00143
00144 static void string_property(GsfOutfile *out, property_list &prop, uint32_t tag, const string &contents);
00145 static void string_property(GsfOutfile *out, property_list &prop, uint32_t tag, const string &contents) {
00146 string_property(out, prop, tag, contents.c_str(), contents.size());
00147 }
00148
00149
00150 static void string_property(GsfOutfile *out, property_list &prop, uint32_t tag, pst_binary &contents);
00151 static void string_property(GsfOutfile *out, property_list &prop, uint32_t tag, pst_binary &contents) {
00152 if (contents.size) string_property(out, prop, tag, contents.data, contents.size);
00153 }
00154
00155
00156 static void write_properties(GsfOutfile *out, property_list &prop, const guint8* header, size_t hlen);
00157 static void write_properties(GsfOutfile *out, property_list &prop, const guint8* header, size_t hlen) {
00158 GsfOutput* dst = gsf_outfile_new_child(out, "__properties_version1.0", false);
00159 gsf_output_write(dst, hlen, header);
00160 for (property_list::iterator i=prop.begin(); i!=prop.end(); i++) {
00161 property &p = *i;
00162 gsf_output_write(dst, sizeof(property), (const guint8*)&p);
00163 }
00164 gsf_output_close(dst);
00165 g_object_unref(G_OBJECT(dst));
00166 }
00167
00168
00169 static void int_property(property_list &prop_list, uint32_t tag, uint32_t flags, uint32_t value);
00170 static void int_property(property_list &prop_list, uint32_t tag, uint32_t flags, uint32_t value) {
00171 property p;
00172 p.tag = tag;
00173 p.flags = flags;
00174 p.length = value;
00175 p.reserved = 0;
00176 prop_list.push_back(p);
00177 }
00178
00179
00180 static void i64_property(property_list &prop_list, uint32_t tag, uint32_t flags, FILETIME *value);
00181 static void i64_property(property_list &prop_list, uint32_t tag, uint32_t flags, FILETIME *value) {
00182 if (value) {
00183 property p;
00184 p.tag = tag;
00185 p.flags = flags;
00186 p.length = value->dwLowDateTime;
00187 p.reserved = value->dwHighDateTime;
00188 prop_list.push_back(p);
00189 }
00190 }
00191
00192
00193 static void nzi_property(property_list &prop_list, uint32_t tag, uint32_t flags, uint32_t value);
00194 static void nzi_property(property_list &prop_list, uint32_t tag, uint32_t flags, uint32_t value) {
00195 if (value) int_property(prop_list, tag, flags, value);
00196 }
00197
00198
00199 void write_msg_email(char *fname, pst_item* item, pst_file* pst) {
00200
00201 if (!item->email) return;
00202 DEBUG_ENT("write_msg_email");
00203
00204 pst_item_email &email = *(item->email);
00205
00206 char charset[30];
00207 const char* body_charset = pst_default_charset(item, sizeof(charset), charset);
00208 DEBUG_INFO(("%s body charset seems to be %s\n", fname, body_charset));
00209 body_charset = "iso-8859-1//TRANSLIT//IGNORE";
00210
00211 gsf_init();
00212
00213 GsfOutfile *outfile;
00214 GsfOutput *output;
00215 GError *err = NULL;
00216
00217 output = gsf_output_stdio_new(fname, &err);
00218 if (output == NULL) {
00219 gsf_shutdown();
00220 DEBUG_INFO(("unable to open output .msg file %s\n", fname));
00221 DEBUG_RET();
00222 return;
00223 }
00224
00225 struct top_property_header {
00226 uint32_t reserved1;
00227 uint32_t reserved2;
00228 uint32_t next_recipient;
00229 uint32_t next_attachment;
00230 uint32_t recipient_count;
00231 uint32_t attachment_count;
00232 uint32_t reserved3;
00233 uint32_t reserved4;
00234 };
00235
00236 top_property_header top_head;
00237 memset(&top_head, 0, sizeof(top_head));
00238
00239 outfile = gsf_outfile_msole_new(output);
00240 g_object_unref(G_OBJECT(output));
00241
00242 output = GSF_OUTPUT(outfile);
00243 property_list prop_list;
00244
00245 int_property(prop_list, 0x00170003, 0x6, email.importance);
00246 nzi_property(prop_list, 0x0023000B, 0x6, email.delivery_report);
00247 nzi_property(prop_list, 0x00260003, 0x6, email.priority);
00248 nzi_property(prop_list, 0x0029000B, 0x6, email.read_receipt);
00249 nzi_property(prop_list, 0x002E0003, 0x6, email.original_sensitivity);
00250 nzi_property(prop_list, 0x00360003, 0x6, email.sensitivity);
00251 nzi_property(prop_list, 0x0C17000B, 0x6, email.reply_requested);
00252 nzi_property(prop_list, 0x0E01000B, 0x6, email.delete_after_submit);
00253 int_property(prop_list, 0x0E070003, 0x6, item->flags);
00254 i64_property(prop_list, 0x00390040, 0x6, email.sent_date);
00255 GsfOutfile *out = GSF_OUTFILE (output);
00256 string_property(out, prop_list, 0x001A001E, item->ascii_type);
00257 string_property(out, prop_list, 0x0037001E, body_charset, item->subject);
00258 strin0_property(out, prop_list, 0x003B0102, body_charset, email.outlook_sender);
00259 string_property(out, prop_list, 0x003D001E, string(""));
00260 string_property(out, prop_list, 0x0040001E, body_charset, email.outlook_received_name1);
00261 string_property(out, prop_list, 0x0042001E, body_charset, email.outlook_sender_name);
00262 string_property(out, prop_list, 0x0044001E, body_charset, email.outlook_recipient_name);
00263 string_property(out, prop_list, 0x0050001E, body_charset, email.reply_to);
00264 strin0_property(out, prop_list, 0x00510102, body_charset, email.outlook_recipient);
00265 strin0_property(out, prop_list, 0x00520102, body_charset, email.outlook_recipient2);
00266 string_property(out, prop_list, 0x0064001E, body_charset, email.sender_access);
00267 string_property(out, prop_list, 0x0065001E, body_charset, email.sender_address);
00268 string_property(out, prop_list, 0x0070001E, body_charset, email.processed_subject);
00269 string_property(out, prop_list, 0x00710102, email.conversation_index);
00270 string_property(out, prop_list, 0x0072001E, body_charset, email.original_bcc);
00271 string_property(out, prop_list, 0x0073001E, body_charset, email.original_cc);
00272 string_property(out, prop_list, 0x0074001E, body_charset, email.original_to);
00273 string_property(out, prop_list, 0x0075001E, body_charset, email.recip_access);
00274 string_property(out, prop_list, 0x0076001E, body_charset, email.recip_address);
00275 string_property(out, prop_list, 0x0077001E, body_charset, email.recip2_access);
00276 string_property(out, prop_list, 0x0078001E, body_charset, email.recip2_address);
00277 string_property(out, prop_list, 0x007D001E, body_charset, email.header);
00278 string_property(out, prop_list, 0x0C1A001E, body_charset, email.outlook_sender_name2);
00279 strin0_property(out, prop_list, 0x0C1D0102, body_charset, email.outlook_sender2);
00280 string_property(out, prop_list, 0x0C1E001E, body_charset, email.sender2_access);
00281 string_property(out, prop_list, 0x0C1F001E, body_charset, email.sender2_address);
00282 string_property(out, prop_list, 0x0E02001E, body_charset, email.bcc_address);
00283 string_property(out, prop_list, 0x0E03001E, body_charset, email.cc_address);
00284 string_property(out, prop_list, 0x0E04001E, body_charset, email.sentto_address);
00285 string_property(out, prop_list, 0x0E1D001E, body_charset, email.outlook_normalized_subject);
00286 string_property(out, prop_list, 0x1000001E, body_charset, item->body);
00287 string_property(out, prop_list, 0x1013001E, body_charset, email.htmlbody);
00288 string_property(out, prop_list, 0x1035001E, body_charset, email.messageid);
00289 string_property(out, prop_list, 0x1042001E, body_charset, email.in_reply_to);
00290 string_property(out, prop_list, 0x1046001E, body_charset, email.return_path_address);
00291
00292
00293
00294 {
00295 vector<char> n(50);
00296 {
00297 snprintf(&n[0], n.size(), "__recip_version1.0_#%08X", top_head.recipient_count);
00298 GsfOutput *output = gsf_outfile_new_child(out, &n[0], true);
00299 {
00300 int v = 1;
00301 property_list prop_list;
00302 int_property(prop_list, 0x0C150003, 0x6, v);
00303 int_property(prop_list, 0x30000003, 0x6, top_head.recipient_count);
00304 GsfOutfile *out = GSF_OUTFILE (output);
00305 string_property(out, prop_list, 0x3001001E, body_charset, item->file_as);
00306 if (item->contact) {
00307 string_property(out, prop_list, 0x3002001E, body_charset, item->contact->address1_transport);
00308 string_property(out, prop_list, 0x3003001E, body_charset, item->contact->address1);
00309 string_property(out, prop_list, 0x5ff6001E, body_charset, item->contact->address1);
00310 }
00311 strin0_property(out, prop_list, 0x300B0102, body_charset, email.outlook_search_key);
00312 write_properties(out, prop_list, (const guint8*)&top_head, 8);
00313 gsf_output_close(output);
00314 g_object_unref(G_OBJECT(output));
00315 top_head.next_recipient++;
00316 top_head.recipient_count++;
00317 }
00318 }
00319 if (email.cc_address.str) {
00320 snprintf(&n[0], n.size(), "__recip_version1.0_#%08X", top_head.recipient_count);
00321 GsfOutput *output = gsf_outfile_new_child(out, &n[0], true);
00322 {
00323 int v = 2;
00324 property_list prop_list;
00325 int_property(prop_list, 0x0C150003, 0x6, v);
00326 int_property(prop_list, 0x30000003, 0x6, top_head.recipient_count);
00327 GsfOutfile *out = GSF_OUTFILE (output);
00328 string_property(out, prop_list, 0x3001001E, body_charset, email.cc_address);
00329 string_property(out, prop_list, 0x3003001E, body_charset, email.cc_address);
00330 string_property(out, prop_list, 0x5ff6001E, body_charset, email.cc_address);
00331 write_properties(out, prop_list, (const guint8*)&top_head, 8);
00332 gsf_output_close(output);
00333 g_object_unref(G_OBJECT(output));
00334 top_head.next_recipient++;
00335 top_head.recipient_count++;
00336 }
00337 }
00338 if (email.bcc_address.str) {
00339 snprintf(&n[0], n.size(), "__recip_version1.0_#%08X", top_head.recipient_count);
00340 GsfOutput *output = gsf_outfile_new_child(out, &n[0], true);
00341 {
00342 int v = 3;
00343 property_list prop_list;
00344 int_property(prop_list, 0x0C150003, 0x6, v);
00345 int_property(prop_list, 0x30000003, 0x6, top_head.recipient_count);
00346 GsfOutfile *out = GSF_OUTFILE (output);
00347 string_property(out, prop_list, 0x3001001E, body_charset, email.bcc_address);
00348 string_property(out, prop_list, 0x3003001E, body_charset, email.bcc_address);
00349 string_property(out, prop_list, 0x5ff6001E, body_charset, email.bcc_address);
00350 write_properties(out, prop_list, (const guint8*)&top_head, 8);
00351 gsf_output_close(output);
00352 g_object_unref(G_OBJECT(output));
00353 top_head.next_recipient++;
00354 top_head.recipient_count++;
00355 }
00356 }
00357 }
00358
00359 pst_item_attach *a = item->attach;
00360 while (a) {
00361 if (a->method == PST_ATTACH_EMBEDDED) {
00362
00363 }
00364 else if (a->data.data || a->i_id) {
00365 vector<char> n(50);
00366 snprintf(&n[0], n.size(), "__attach_version1.0_#%08X", top_head.attachment_count);
00367 GsfOutput *output = gsf_outfile_new_child(out, &n[0], true);
00368 {
00369 FILE *fp = fopen("temp_file_attachment", "w+b");
00370 if (fp) {
00371 pst_attach_to_file(pst, a, fp);
00372 fseek(fp, 0, SEEK_SET);
00373 property_list prop_list;
00374 int_property(prop_list, 0x0E210003, 0x2, top_head.attachment_count);
00375 int_property(prop_list, 0x0FF40003, 0x2, 2);
00376 int_property(prop_list, 0x0FF70003, 0x2, 0);
00377 int_property(prop_list, 0x0FFE0003, 0x2, 7);
00378 int_property(prop_list, 0x37050003, 0x7, 1);
00379 int_property(prop_list, 0x370B0003, 0x7, a->position);
00380 int_property(prop_list, 0x37100003, 0x6, a->sequence);
00381 GsfOutfile *out = GSF_OUTFILE (output);
00382 string_property(out, prop_list, 0x0FF90102, item->record_key);
00383 string_property(out, prop_list, 0x37010102, fp);
00384 if (a->filename2.str) {
00385
00386 string_property(out, prop_list, 0x3707001E, body_charset, a->filename2);
00387 }
00388 else if (a->filename1.str) {
00389
00390 string_property(out, prop_list, 0x3704001E, body_charset, a->filename1);
00391 }
00392 else {
00393
00394 const char *n = "inline";
00395 string_property(out, prop_list, 0x3704001E, n, strlen(n));
00396 }
00397 string_property(out, prop_list, 0x370E001E, body_charset, a->mimetype);
00398 write_properties(out, prop_list, (const guint8*)&top_head, 8);
00399 gsf_output_close(output);
00400 g_object_unref(G_OBJECT(output));
00401 top_head.next_attachment++;
00402 top_head.attachment_count++;
00403 fclose(fp);
00404 }
00405 }
00406 }
00407 a = a->next;
00408 }
00409
00410 write_properties(out, prop_list, (const guint8*)&top_head, sizeof(top_head));
00411
00412 {
00413 GsfOutput *output = gsf_outfile_new_child(out, "__nameid_version1.0", true);
00414 {
00415 GsfOutfile *out = GSF_OUTFILE (output);
00416 empty_property(out, 0x00020102);
00417 empty_property(out, 0x00030102);
00418 empty_property(out, 0x00040102);
00419 gsf_output_close(output);
00420 g_object_unref(G_OBJECT(output));
00421 }
00422 }
00423
00424 gsf_output_close(output);
00425 g_object_unref(G_OBJECT(output));
00426
00427 gsf_shutdown();
00428 DEBUG_RET();
00429 }
00430