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