modules/ep/mail_parser.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- InitializeMailDescr
- EP_ParseMail
- EP_ParseText
- EP_MIMEParse
- EP_InitializeRootNode
- EP_InitializeNode
- EP_DefineNewNode
- EP_TreeCleanUp
- MailHeaderFieldCleanUp
- EP_MailDescrCleanUp
- EP_BuildFilename
- EP_ShowTree
- EP_DefineNewToken
- AddKeyInfo
- RemoveKeyInfo
- EP_GetTokens
- EP_PrintTokens
- EP_CleanTokens
1 /***************************************
2 $Revision: 1.22 $
3
4 Email Parser module (ep) - wrapping functions to parse email,
5 calling MM and PA.
6
7 Status: NOT REVUED, TESTED
8
9 ******************/ /******************
10 Filename : mail_parser.c
11 Authors : filippo@ripe.net
12 OSs Tested : Solaris 7
13 ******************/ /******************
14 Copyright (c) 2000 RIPE NCC
15
16 All Rights Reserved
17
18 Permission to use, copy, modify, and distribute this software and its
19 documentation for any purpose and without fee is hereby granted,
20 provided that the above copyright notice appear in all copies and that
21 both that copyright notice and this permission notice appear in
22 supporting documentation, and that the name of the author not be
23 used in advertising or publicity pertaining to distribution of the
24 software without specific, written prior permission.
25
26 THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
27 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
28 AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
29 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
30 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
31 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32 ***************************************/
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <netdb.h>
38 #include <sys/param.h>
39
40 #include "mm.h"
41 #include "gpg.h"
42 #include "mail_parser.h"
43
44 /* Parse the mail message stored in inputFile and develop it
45 in distinct text files, writing them on the outputPath
46 directory and using the variable keyRing to read public
47 keys needed for the verification process.
48
49 The common use of this parse should look like this:
50
51 p = EP_ParseMessage("mail.001", "/tmp", "~/.gnupg/pubring.gpg");
52
53 < parse the tree: p->tree >
54
55 EP_TreeCleanUp(p);
56
57 */
58
59 /* Globals to store shared data for tree nodes */
60
61 char EP_outputPrefix[FILENAME_LENGTH];
62 char EP_keyRing[FILENAME_LENGTH];
63 int EP_TreeHeight;
64 int EP_Node_ID;
65 int EP_Debug;
66
67 const char *vS_strRC[] = { "IS_VALID",
68 "IS_NOT_PGP",
69 "KO",
70 "CRC_ERROR",
71 "NO_PUBLIC_KEY",
72 "NO_OPENPGP_DATA",
73 "NO_IN_FILES",
74 "NO_OUT_FILES",
75 "TO_BE_PGPVERIFIED",
76 "UNABLE_TO_WRITE_FILE",
77 "UNMATCHED_PGP_DELIMITERS"
78 };
79
80 #define EP_TREEMAXHEIGHT 10;
81
82 EP_Mail_DescrPtr InitializeMailDescr( const char *inputFile ) {
/* [<][>][^][v][top][bottom][index][help] */
83
84 EP_Mail_DescrPtr ptr;
85 /* EPNodePtr rootNode; */
86 int retcode;
87 long debug = 0;
88
89 ptr = malloc(sizeof(EP_Mail_Descr));
90
91 ptr->from = ptr->subject = ptr->date =
92 ptr->message_id = ptr->reply_to = ptr->cc =
93 ptr->content_type = NULL ;
94
95
96 /* Obtain headers */
97 retcode = MM_get_headers(inputFile, ptr, debug);
98
99 ptr->tree = EP_InitializeRootNode(inputFile);
100
101 return ptr;
102 }
103
104 /* ------------------------------------------------- */
105
106 EP_Mail_DescrPtr EP_ParseMail(const char *inputFile,
/* [<][>][^][v][top][bottom][index][help] */
107 const char *outputPath,
108 const char *keyRing) {
109 EP_Mail_DescrPtr ptr;
110 char hostname[MAXHOSTNAMELEN];
111 int retcode;
112 long debug = 0;
113 char mail_file[FILENAMELEN];
114
115 EP_Debug = debug;
116
117 gethostname(hostname, MAXHOSTNAMELEN);
118 sprintf(EP_outputPrefix, "%s/EPMtmp.%s.%ld.", outputPath,
119 hostname, getpid());
120 strcpy(EP_keyRing, keyRing);
121
122 sprintf (mail_file,"%sunprocessed", EP_outputPrefix); /* the file where the mail message will be stored */
123
124 /* if ((retcode = MM_store((char*)inputFile,mail_file, debug)) != 0)
125 exit (retcode); */
126
127 MM_store((char*)inputFile,mail_file, debug);
128
129 ptr = InitializeMailDescr(mail_file);
130 /* Invoke the MIME parser */
131 retcode = MM_extract_mime(mail_file, NULL, ptr->tree, debug);
132
133 return ptr;
134 }
135
136 /* ------------------------------------------------- */
137
138 EPNodePtr EP_ParseText(const char *inputFile,
/* [<][>][^][v][top][bottom][index][help] */
139 const char *outputPath,
140 const char *keyRing) {
141 EPNodePtr ptr;
142 char hostname[MAXHOSTNAMELEN];
143
144 EP_Debug = 0;
145
146 gethostname(hostname, MAXHOSTNAMELEN);
147 sprintf(EP_outputPrefix, "%s/EPTtmp.%s.%ld.", outputPath,
148 hostname, getpid());
149
150 strcpy(EP_keyRing, keyRing);
151
152 ptr = EP_InitializeRootNode(inputFile);
153
154 return PA_ParseMessage(ptr);
155 }
156
157
158 /* ------------------------------------------------- */
159
160 EPNodePtr EP_MIMEParse(const EPNodePtr p)
/* [<][>][^][v][top][bottom][index][help] */
161 {
162 char mail_file[FILENAMELEN];
163 int retcode;
164 FILE * fin;
165 char *strptr;
166 int found = 0, headers_end = 0;
167 char txt[MAX_LINE_BUF];
168
169 sprintf (mail_file,"%s%d.unprocessed", EP_outputPrefix, p->nodeID); /* the file where the mail message will be stored */
170
171 /* Quest for a mail header:
172 look for a mail header of type (content-type || mime version).
173 */
174
175 if ((fin = fopen(p->file, "r")) != NULL) {
176 while ( !headers_end && !found &&
177 (strptr = fgets(txt, MAX_LINE_BUF, fin)) != NULL) {
178 if ( do_regex_test("^Content-Type:", txt) ||
179 do_regex_test("^MIME-Version:", txt)) {
180 found = 1;
181 fclose(fin);
182
183 /* if ((retcode = MM_store((char*)p->file,mail_file, EP_Debug)) != 0) {
184 fprintf(stderr, "Error on MM_Store: %d\n", retcode );
185 } */
186
187 MM_store((char*)p->file,mail_file, EP_Debug);
188
189 /* Invoke the MIME parser */
190 retcode = MM_extract_mime(mail_file, NULL, p, EP_Debug);
191 } else
192 if ( do_regex_test("^ *\n", txt) )
193 headers_end = 1;
194 }
195
196 if (!found) {
197 fclose(fin);
198 PA_ParseMessage(p);
199 }
200
201 } else {
202 p->isValidPGPSignature = vS_NO_IN_FILES;
203 }
204
205 return p;
206 }
207
208 /* ------------------------------------------------- */
209
210 EPNodePtr EP_InitializeRootNode( const char *inputFile ) {
/* [<][>][^][v][top][bottom][index][help] */
211 EPNodePtr rootNode;
212
213 EP_TreeHeight = EP_Node_ID = 0;
214
215 rootNode = malloc(sizeof(struct EPNode));
216
217 rootNode->nodeID = 0;
218 rootNode->isValidPGPSignature = vS_IS_NOT_PGP;
219 rootNode->keyID = 0;
220 rootNode->MIMEContentType = -1;
221 rootNode->strMIMEContentType = NULL;
222 rootNode->file = strdup(inputFile);
223 rootNode->inner = NULL;
224 rootNode->next = NULL;
225
226 return rootNode;
227 }
228
229 /* ------------------------------------------------- */
230
231 EPNodePtr EP_InitializeNode( const char *inputFile, const int nodeID ) {
/* [<][>][^][v][top][bottom][index][help] */
232 EPNodePtr node;
233
234 node = malloc(sizeof(struct EPNode));
235
236 node->nodeID = nodeID;
237 node->isValidPGPSignature = vS_IS_NOT_PGP;
238 node->keyID = 0;
239 node->MIMEContentType = -1;
240 node->strMIMEContentType = NULL;
241 node->file = strdup(inputFile);
242 node->inner = NULL;
243 node->next = NULL;
244
245 return node;
246 }
247
248 /* ------------------------------------------------- */
249
250 EPNodePtr EP_DefineNewNode( const int nodeID,
/* [<][>][^][v][top][bottom][index][help] */
251 const short isValidPGPSignature,
252 const t_MM_type MIMEContentType,
253 const char *strMIMEContentType,
254 const u32 keyID) {
255 EPNodePtr node;
256
257 node = (EPNodePtr) malloc(sizeof(EP_mail_node));
258
259 /* printf("node: %d, %p\n", nodeID, node); */
260
261 node->nodeID = nodeID;
262 node->isValidPGPSignature = isValidPGPSignature;
263 node->keyID = keyID;
264 node->MIMEContentType = MIMEContentType;
265 node->strMIMEContentType = (strMIMEContentType == NULL ? NULL :
266 strdup(strMIMEContentType) );
267 node->inner = NULL;
268 node->next = NULL;
269 EP_BuildFilename(node);
270
271 return node;
272 }
273
274 /* ------------------------------------------------- */
275 /* Deallocate parsing tree and remove files */
276
277 void EP_TreeCleanUp(const EPNodePtr ptr) {
/* [<][>][^][v][top][bottom][index][help] */
278
279 if (ptr->file != NULL) {
280 /* unlink(ptr->file); */
281 /* printf("node: %d, %p\n", ptr->nodeID, ptr); */
282 free(ptr->file);
283 }
284 if (ptr->strMIMEContentType != NULL) {
285 free(ptr->strMIMEContentType);
286 }
287
288 if (ptr->inner != NULL) EP_TreeCleanUp(ptr->inner);
289 if (ptr->next != NULL) EP_TreeCleanUp(ptr->next);
290
291 free(ptr);
292 }
293
294 /* ------------------------------------------------- */
295 void MailHeaderFieldCleanUp(Mail_Header_FieldPtr p) {
/* [<][>][^][v][top][bottom][index][help] */
296 Mail_Header_FieldPtr ptmp = p, prev;
297
298 while (ptmp != NULL) {
299 prev = ptmp;
300 ptmp = ptmp->next;
301 if (prev->field != NULL)
302 free(prev->field);
303 free(prev);
304 }
305 }
306
307
308 /* ------------------------------------------------- */
309
310 /* Deallocate parsing tree and remove files */
311
312 void EP_MailDescrCleanUp(const EP_Mail_DescrPtr ptr) {
/* [<][>][^][v][top][bottom][index][help] */
313
314 if (ptr != NULL) {
315
316 MailHeaderFieldCleanUp(ptr->from);
317 MailHeaderFieldCleanUp(ptr->subject);
318 MailHeaderFieldCleanUp(ptr->date);
319 MailHeaderFieldCleanUp(ptr->message_id);
320 MailHeaderFieldCleanUp(ptr->reply_to);
321 MailHeaderFieldCleanUp(ptr->cc);
322 MailHeaderFieldCleanUp(ptr->content_type);
323
324 EP_TreeCleanUp(ptr->tree);
325 free(ptr);
326 }
327 }
328
329 /* ------------------------------------------------- */
330 /* Build a node filename */
331
332 void EP_BuildFilename(const EPNodePtr ptr) {
/* [<][>][^][v][top][bottom][index][help] */
333 char file[FILENAME_LENGTH];
334
335 sprintf(file, "%s%d", EP_outputPrefix, ptr->nodeID);
336 ptr->file = strdup(file);
337 }
338
339 /* ------------------------------------------------- */
340
341 void EP_ShowTree(const EPNodePtr p) {
/* [<][>][^][v][top][bottom][index][help] */
342 if (p != NULL) {
343 if (EP_HasContent(p)) {
344 printf("Node ID: %d\n", p->nodeID);
345 printf("isValidPGPSignature: %s\n", vS_strRC[p->isValidPGPSignature]);
346 printf("MIMEContentType: %d\n", p->MIMEContentType);
347 printf("Key ID: %0X\n", p->keyID);
348 printf("file: %s\n\n\n", p->file);
349 }
350 if (p->inner != NULL)
351 EP_ShowTree(p->inner);
352 if (p->next != NULL)
353 EP_ShowTree(p->next);
354 }
355 }
356
357 /* ------------------------------------------------- */
358
359 EPTokenPtr EP_DefineNewToken( const t_MM_type MIMEContentType,
/* [<][>][^][v][top][bottom][index][help] */
360 const char *file,
361 const EPTokenKeysPtr keysList ) {
362 EPTokenPtr token;
363 EPTokenKeysPtr head = NULL, p = keysList, pnew, prev = NULL;
364
365 token = (EPTokenPtr) malloc(sizeof(EPToken));
366 token->file = (char*)file;
367 token->MIMEContentType = MIMEContentType;
368
369
370 /* generate head, and build the key list for this result node */
371 if (p != NULL) {
372 pnew = (EPTokenKeysPtr) malloc(sizeof(EPTokenKeys));
373 pnew->isValidPGPSignature = p->isValidPGPSignature;
374 pnew->keyID = p->keyID;
375 pnew->next = NULL;
376 head = prev = pnew;
377 p = p->next;
378 }
379
380 while (p != NULL) {
381 pnew = (EPTokenKeysPtr) malloc(sizeof(EPTokenKeys));
382 pnew->isValidPGPSignature = p->isValidPGPSignature;
383 pnew->keyID = p->keyID;
384 pnew->next = NULL;
385 prev->next = pnew;
386 prev = pnew;
387 p = p->next;
388 }
389
390 token->keys = head;
391 token->next = token->prev = NULL;
392
393 return token;
394 }
395
396 /* ------------------------------------------------- */
397
398 EPTokenKeysPtr AddKeyInfo( EPTokenKeysPtr keysList, const EPNodePtr p ){
/* [<][>][^][v][top][bottom][index][help] */
399 EPTokenKeysPtr ptk;
400
401 ptk = (EPTokenKeysPtr) malloc(sizeof(EPTokenKeys));
402 ptk->isValidPGPSignature = p->isValidPGPSignature;
403 ptk->keyID = p->keyID;
404 ptk->next = NULL;
405 if (keysList == NULL)
406 return ptk;
407 else {
408 ptk->next = keysList;
409 return ptk;
410 }
411 }
412
413 /* ------------------------------------------------- */
414
415 EPTokenKeysPtr RemoveKeyInfo( const EPTokenKeysPtr keysHead ) {
/* [<][>][^][v][top][bottom][index][help] */
416 EPTokenKeysPtr tmp = keysHead->next;
417
418 free(keysHead);
419 return tmp;
420 }
421 /* ------------------------------------------------- */
422
423 EPTokenPtr EP_GetTokens(const EPNodePtr p, const EPTokenPtr head,
/* [<][>][^][v][top][bottom][index][help] */
424 EPTokenKeysPtr keysList) {
425 EPTokenPtr pt, ptmp = head;
426 EPTokenKeysPtr kl = keysList;
427
428 if (p != NULL) {
429 if (p->isValidPGPSignature != vS_IS_NOT_PGP ) {
430 kl = AddKeyInfo(kl, p);
431 }
432 if (EP_HasContent(p)) {
433 pt = EP_DefineNewToken(p->MIMEContentType, p->file, kl);
434 if (ptmp != NULL) {
435 pt->next = ptmp;
436 ptmp->prev = pt;
437 ptmp = pt;
438 } else
439 ptmp = pt;
440 } else
441 ptmp = EP_GetTokens(p->inner, ptmp, kl);
442
443 if (p->isValidPGPSignature != vS_IS_NOT_PGP ) {
444 kl = RemoveKeyInfo(kl);
445 }
446
447 ptmp = EP_GetTokens(p->next, ptmp, kl);
448 }
449 return ptmp;
450 }
451
452 /* ------------------------------------------------- */
453 void EP_PrintTokens(EPTokenPtr head) {
/* [<][>][^][v][top][bottom][index][help] */
454 EPTokenPtr p = head;
455 EPTokenKeysPtr ptk;
456
457 while (p != NULL) {
458 printf("Token: %s, MIMEtype: %d\n", p->file, p->MIMEContentType);
459 ptk = p->keys;
460 while (ptk != NULL) {
461 printf(" key: %0X, isValid: %s\n",
462 ptk->keyID, vS_strRC[ptk->isValidPGPSignature]);
463 ptk = ptk->next;
464 }
465 p = p->next;
466 }
467 }
468
469 /* ------------------------------------------------- */
470
471 void EP_CleanTokens(const EPTokenPtr head) {
/* [<][>][^][v][top][bottom][index][help] */
472 EPTokenPtr prevp, p = head;
473 EPTokenKeysPtr ptk, prevptk;
474
475 while (p != NULL) {
476 ptk = p->keys;
477 while (ptk != NULL) {
478 prevptk = ptk;
479 ptk = ptk->next;
480 free(prevptk);
481 }
482 prevp = p;
483 p = p->next;
484 free(prevp);
485 }
486 }
487
488