* New upstream release.
[debian/mimetic.git] / examples / smime2xml.cxx
1 #include <iostream>
2 #include <fstream>
3 #include <sstream>
4 #include <iterator>
5 #include <streambuf>
6 #include <mimetic/mimetic.h>
7 #include <mimetic/utils.h>
8 #include <openssl/bio.h>
9 #include <openssl/pkcs7.h>
10 #include <openssl/x509.h>
11 #include <openssl/err.h>
12 #include <openssl/ssl.h>
13
14 using namespace std;
15 using namespace mimetic;
16
17 void printMimeStructure(MimeEntity* pMe, int tabcount = 0);
18
19 int g_verbose; // verbose mode on/off
20 int g_quiet; // quiet mode
21
22 void printTabs(int c)
23 {
24     while(c--)
25         cout << "    ";
26 }
27
28 int bca_pkcs7_verify(PKCS7 *p7)
29 {
30     return ~0;
31 }
32
33 int pkcs7MimeHandle(MimeEntity* pMe, int tabcount)
34 {
35     BIO *in = NULL, *content = NULL;
36     PKCS7 *p7 = NULL;
37     long sz;
38     char *pdata = NULL;
39     int rc = ~0, vfy, iMask = imPreamble | imEpilogue;
40     string me_str;
41     Header& h = pMe->header();
42     ContentType ct = h.contentType();
43
44     {
45     stringstream ss;
46     ss << *pMe;
47     me_str = ss.str();
48     }
49
50     in = BIO_new_mem_buf((void*)me_str.c_str(), me_str.length());
51     if(in == NULL)
52         goto err;
53     BIO_set_mem_eof_return(in, 0);
54
55     p7 = SMIME_read_PKCS7(in, &content);
56     if(p7 == NULL)
57         goto err;
58
59     vfy = bca_pkcs7_verify(p7);
60
61     if(content == NULL)
62     { 
63         content = PKCS7_dataInit(p7, NULL);
64         if(content == NULL)
65             goto err;
66     } else {
67         ; /* multipart/signed, content is the cleartext message part */
68         goto err;
69     }
70     
71     sz = BIO_get_mem_data(content, &pdata);
72     if(sz > 0 && pdata)
73     {
74         MimeEntity me(pdata, pdata + sz, iMask);
75         printMimeStructure(&me, 1 + tabcount);
76     }
77
78     /* success */
79     rc = 0;
80 err:
81     if(in)
82         BIO_free(in);
83     if(content)
84         BIO_free(content);
85     if(p7)
86         PKCS7_free(p7);
87     if(rc)
88         ERR_print_errors_fp(stderr);
89     return rc;
90 }
91
92 void printMimeStructure(MimeEntity* pMe, int tabcount)
93 {
94     Header& h = pMe->header();
95     ContentType ct = h.contentType();
96     ContentId ci = h.contentId();
97     ContentDisposition cd = h.contentDisposition();
98     ContentDescription cds = h.contentDescription();
99
100     cout << "<mime-content>" << endl;
101     cout << "<mime-info>" << endl;
102     cout << "<content-type>" << 
103         ct.type() << "/" << ct.subtype() << 
104         "</content-type>" << endl;
105     if(ci.str().length())
106         ;//cout << "<content-id>" << ci.str() << "</content-id>" << endl;
107     if(h.hasField("subject"))
108         cout << "<subject>" << h.field("subject").value() << "</subject>" << 
109             endl;
110     if(cd.param("filename").length())
111         cout << "<filename>" << cd.param("filename") << "</filename>" << 
112             endl;
113     if(cds.str().length())
114         cout << "<description>" << cds.str() << "</description>" << endl;
115
116     cout << "</mime-info>" << endl;
117
118     if(ct.isMultipart() || 
119         (ct.type() == "message" && ct.subtype() == "rfc822"))
120     {
121         if(ct.subtype() == "signed")
122         {
123             cerr << "S/MIME multipart/signed not yet supported!" << endl;
124             exit(1);
125         } else {
126             //printTabs(tabcount);
127             //cout << ct.type() << "/" << ct.subtype() << endl;
128
129             MimeEntityList::iterator mbit = pMe->body().parts().begin(),
130                             meit = pMe->body().parts().end();
131             cout << "<structured-data>" << endl;
132             for(; mbit != meit; ++mbit)
133             {
134                 printMimeStructure(*mbit, 1 + tabcount);
135             }
136             cout << "</structured-data>" << endl;
137         }
138     } else {
139         if(ct.type() == "application" && 
140             (ct.subtype() == "x-pkcs7-mime" || ct.subtype() == "pkcs7-mime"))
141         {
142             cout << "<structured-data>" << endl;
143             pkcs7MimeHandle(pMe, tabcount);
144             cout << "</structured-data>" << endl;
145         } else {
146             ;//printTabs(tabcount);
147             ;//cout << ct.type() << "/" << ct.subtype() << endl;
148         }
149     }
150     cout << "</mime-content>" << endl;
151 }
152
153 void usage()
154 {
155     cout << "smime2xml in_file" << endl;
156     cout << "    -v Verbose mode" << endl;
157     cout << "    -q totaly quiet; exit code = num of entities" << endl;
158     cout << endl;
159     exit(1);
160 }
161
162 int main(int argc, char** argv)
163 {
164     std::ios_base::sync_with_stdio(false);
165     int fidx = 1;
166     int iMask = imPreamble | imEpilogue;
167
168     /* Initialize the OpenSSL engine.  */
169     CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
170     OpenSSL_add_all_algorithms();
171     ERR_load_crypto_strings();
172
173     if(argc > 1)
174     {    
175         g_verbose = 0;
176         string first = argv[1];
177         if(first == "-h")
178             usage();
179         else if(first == "-v")
180             g_verbose = 1;
181         else if(first == "-q")
182             g_quiet = 1;
183         fidx = (g_verbose || g_quiet ? 2 : 1); // first filename idx
184     }
185     if(argc == fidx)
186     {
187         istreambuf_iterator<char> bit(std::cin), eit;
188         MimeEntity me(bit,eit, iMask);
189         printMimeStructure(&me);
190     } else {
191         for(int fc = fidx; fc < argc; ++fc)
192         {
193             File in(argv[fc]);
194             if(!in)
195             {
196                 cerr << "ERR: unable to open file " 
197                     << argv[fc]
198                     << endl;
199                 continue;
200             }
201             MimeEntity me(in.begin(), in.end(),iMask);
202             if(!me.header().hasField("content-type"))
203             {   /* no content-type found, consider it a CMS */
204                 me.header().contentType().set("application/x-pkcs7-mime");
205             }
206             printMimeStructure(&me);
207         }
208     }
209     return 0;
210 }
211