msg.cpp

Go to the documentation of this file.
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; // or value
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;  // null
00038     if (!str.is_utf8) return;  // not utf8
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         // unable to convert, change the charset to utf8
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         // null terminate the output string
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;  // null terminator
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;   // make all the properties writable
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;   // make all the properties writable
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     // this is not an email item
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;   // same as recipient count
00229         uint32_t  next_attachment;  // same as attachment count
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     // any property over 0x8000 needs entries in the __nameid to make them
00292     // either string named or numerical named properties.
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;  // to
00301                 property_list prop_list;
00302                 int_property(prop_list, 0x0C150003, 0x6, v);                        // PidTagRecipientType
00303                 int_property(prop_list, 0x30000003, 0x6, top_head.recipient_count); // PR_ROWID
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);  // convenient 8 bytes of reserved zeros
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;  // cc
00324                 property_list prop_list;
00325                 int_property(prop_list, 0x0C150003, 0x6, v);                        // PidTagRecipientType
00326                 int_property(prop_list, 0x30000003, 0x6, top_head.recipient_count); // PR_ROWID
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);  // convenient 8 bytes of reserved zeros
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;  // bcc
00343                 property_list prop_list;
00344                 int_property(prop_list, 0x0C150003, 0x6, v);                        // PidTagRecipientType
00345                 int_property(prop_list, 0x30000003, 0x6, top_head.recipient_count); // PR_ROWID
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);  // convenient 8 bytes of reserved zeros
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             // not implemented yet
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); // data is now in the file
00372                     fseek(fp, 0, SEEK_SET);
00373                     property_list prop_list;
00374                     int_property(prop_list, 0x0E210003, 0x2, top_head.attachment_count);    // MAPI_ATTACH_NUM
00375                     int_property(prop_list, 0x0FF40003, 0x2, 2);            // PR_ACCESS read
00376                     int_property(prop_list, 0x0FF70003, 0x2, 0);            // PR_ACCESS_LEVEL read only
00377                     int_property(prop_list, 0x0FFE0003, 0x2, 7);            // PR_OBJECT_TYPE attachment
00378                     int_property(prop_list, 0x37050003, 0x7, 1);            // PR_ATTACH_METHOD by value
00379                     int_property(prop_list, 0x370B0003, 0x7, a->position);  // PR_RENDERING_POSITION
00380                     int_property(prop_list, 0x37100003, 0x6, a->sequence);  // PR_ATTACH_MIME_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                         // have long file name
00386                         string_property(out, prop_list, 0x3707001E, body_charset, a->filename2);
00387                     }
00388                     else if (a->filename1.str) {
00389                         // have short file name
00390                         string_property(out, prop_list, 0x3704001E, body_charset, a->filename1);
00391                     }
00392                     else {
00393                         // make up a name
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);  // convenient 8 bytes of reserved zeros
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 

Generated on 6 Jul 2016 for 'LibPst' by  doxygen 1.6.1