/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
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_GetPasswords
- EP_GetTokens
- EP_PrintTokens
- EP_CleanTokens
1 /***************************************
2 $Revision: 1.33 $
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 Portera, Daniele Arena
12 OSs Tested : Solaris 7
13 ******************/ /******************
14 Copyright (c) 2000,2001,2002 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 char EP_gpgcmd[FILENAME_LENGTH]; */
64 int EP_TreeHeight;
65 int EP_Node_ID;
66 int EP_Debug;
67
68 const char *vS_strRC[] = { "IS_VALID",
69 "IS_NOT_PGP",
70 "KO",
71 "CRC_ERROR",
72 "NO_PUBLIC_KEY",
73 "NO_OPENPGP_DATA",
74 "NO_IN_FILES",
75 "NO_OUT_FILES",
76 "TO_BE_PGPVERIFIED",
77 "UNABLE_TO_WRITE_FILE",
78 "UNMATCHED_PGP_DELIMITERS"
79 };
80
81 #define EP_TREEMAXHEIGHT 10;
82
83 EP_Mail_DescrPtr InitializeMailDescr( const char *inputFile ) {
/* [<][>][^][v][top][bottom][index][help] */
84
85 EP_Mail_DescrPtr ptr;
86 /* EPNodePtr rootNode; */
87 int retcode;
88 long debug = 0;
89
90 ptr = UT_malloc(sizeof(EP_Mail_Descr));
91
92 ptr->from = ptr->subject = ptr->date =
93 ptr->message_id = ptr->reply_to = ptr->cc =
94 ptr->content_type = NULL ;
95
96
97 /* Obtain headers */
98 retcode = MM_get_headers(inputFile, ptr, debug);
99
100 ptr->tree = EP_InitializeRootNode(inputFile);
101
102 return ptr;
103 }
104
105 /* ------------------------------------------------- */
106
107 EP_Mail_DescrPtr EP_ParseMail(const char *inputFile,
/* [<][>][^][v][top][bottom][index][help] */
108 const char *outputPath) {
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.%d.", outputPath,
119 hostname, getpid());
120 PA_SetOutputPrefix(EP_outputPrefix);
121
122 /*
123 strcpy(EP_keyRing, keyRing);
124 strcpy(EP_gpgcmd, gpgcmd);
125 */
126
127 sprintf (mail_file,"%sunprocessed", EP_outputPrefix); /* the file where the mail message will be stored */
128
129 /* if ((retcode = MM_store((char*)inputFile,mail_file, debug)) != 0)
130 exit (retcode); */
131
132 MM_store((char*)inputFile,mail_file, debug, 0);
133
134 ptr = InitializeMailDescr(mail_file);
135 /* Invoke the MIME parser */
136 retcode = MM_extract_mime(mail_file, NULL, ptr->tree, debug);
137
138 return ptr;
139 }
140
141 /* ------------------------------------------------- */
142
143 EPNodePtr EP_ParseText(const char *inputFile,
/* [<][>][^][v][top][bottom][index][help] */
144 const char *outputPath) {
145 EPNodePtr ptr;
146 char hostname[MAXHOSTNAMELEN];
147
148 EP_Debug = 0;
149
150 gethostname(hostname, MAXHOSTNAMELEN);
151 sprintf(EP_outputPrefix, "%s/EPTtmp.%s.%d.", outputPath,
152 hostname, getpid());
153
154 /*
155 strcpy(EP_keyRing, keyRing);
156 strcpy(EP_gpgcmd, gpgcmd);
157 */
158
159 ptr = EP_InitializeRootNode(inputFile);
160
161 PA_SetOutputPrefix(EP_outputPrefix);
162 return PA_ParseMessage(ptr);
163 }
164
165
166 /* ------------------------------------------------- */
167
168 EPNodePtr EP_MIMEParse(const EPNodePtr p)
/* [<][>][^][v][top][bottom][index][help] */
169 {
170 char mail_file[FILENAMELEN];
171 int retcode;
172 FILE * fin;
173 char *strptr;
174 int found = 0, headers_end = 0;
175 char txt[MAX_LINE_BUF];
176
177 sprintf (mail_file,"%s%d.unprocessed", EP_outputPrefix, p->nodeID); /* the file where the mail message will be stored */
178
179 PA_SetOutputPrefix(EP_outputPrefix);
180 /* Quest for a mail header:
181 look for a mail header of type (content-type || mime version).
182 */
183
184 if ((fin = fopen(p->file, "r")) != NULL) {
185 while ( !headers_end && !found &&
186 (strptr = fgets(txt, MAX_LINE_BUF, fin)) != NULL) {
187 if ( do_regex_test("^Content-Type:", txt) ||
188 do_regex_test("^MIME-Version:", txt)) {
189 found = 1;
190 fclose(fin);
191
192 /* if ((retcode = MM_store((char*)p->file,mail_file, EP_Debug)) != 0) {
193 fprintf(stderr, "Error on MM_Store: %d\n", retcode );
194 } */
195
196 MM_store((char*)p->file,mail_file, EP_Debug, 0);
197
198 /* Invoke the MIME parser */
199 retcode = MM_extract_mime(mail_file, NULL, p, EP_Debug);
200 } else
201 if ( do_regex_test("^ *\n", txt) )
202 headers_end = 1;
203 }
204
205 if (!found) {
206 fclose(fin);
207 PA_SetOutputPrefix(EP_outputPrefix);
208
209 PA_ParseMessage(p);
210
211 }
212
213 } else {
214 p->isValidPGPSignature = vS_NO_IN_FILES;
215 }
216
217 return p;
218 }
219
220 /* ------------------------------------------------- */
221
222 EPNodePtr EP_InitializeRootNode( const char *inputFile ) {
/* [<][>][^][v][top][bottom][index][help] */
223 EPNodePtr rootNode;
224
225 EP_TreeHeight = EP_Node_ID = 0;
226
227 rootNode = UT_malloc(sizeof(struct EPNode));
228
229 rootNode->nodeID = 0;
230 rootNode->isValidPGPSignature = vS_IS_NOT_PGP;
231 rootNode->keyID = 0;
232 rootNode->MIMEContentType = -1;
233 rootNode->strMIMEContentType = NULL;
234 rootNode->file = strdup(inputFile);
235 rootNode->inner = NULL;
236 rootNode->next = NULL;
237
238 return rootNode;
239 }
240
241 /* ------------------------------------------------- */
242
243 EPNodePtr EP_InitializeNode( const char *inputFile, const int nodeID ) {
/* [<][>][^][v][top][bottom][index][help] */
244 EPNodePtr node;
245
246 node = UT_malloc(sizeof(struct EPNode));
247
248 node->nodeID = nodeID;
249 node->isValidPGPSignature = vS_IS_NOT_PGP;
250 node->keyID = 0;
251 node->MIMEContentType = -1;
252 node->strMIMEContentType = NULL;
253 node->file = strdup(inputFile);
254 node->inner = NULL;
255 node->next = NULL;
256
257 return node;
258 }
259
260 /* ------------------------------------------------- */
261
262 EPNodePtr EP_DefineNewNode( const int nodeID,
/* [<][>][^][v][top][bottom][index][help] */
263 const short isValidPGPSignature,
264 const t_MM_type MIMEContentType,
265 const char *strMIMEContentType,
266 const u32 keyID) {
267 EPNodePtr node;
268
269 node = (EPNodePtr) UT_malloc(sizeof(EP_mail_node));
270
271 /* printf("node: %d, %p\n", nodeID, node); */
272
273 node->nodeID = nodeID;
274 node->isValidPGPSignature = isValidPGPSignature;
275 node->keyID = keyID;
276 node->MIMEContentType = MIMEContentType;
277 node->strMIMEContentType = (strMIMEContentType == NULL ? NULL :
278 strdup(strMIMEContentType) );
279 node->inner = NULL;
280 node->next = NULL;
281 EP_BuildFilename(node);
282
283 return node;
284 }
285
286 /* ------------------------------------------------- */
287 /* Deallocate parsing tree and remove files */
288
289 void EP_TreeCleanUp(const EPNodePtr ptr) {
/* [<][>][^][v][top][bottom][index][help] */
290
291 if (ptr->file != NULL) {
292 unlink(ptr->file);
293 /* printf("node: %d, %p\n", ptr->nodeID, ptr); */
294 free(ptr->file);
295 }
296 if (ptr->strMIMEContentType != NULL) {
297 free(ptr->strMIMEContentType);
298 }
299
300 if (ptr->inner != NULL) EP_TreeCleanUp(ptr->inner);
301 if (ptr->next != NULL) EP_TreeCleanUp(ptr->next);
302
303 free(ptr);
304 }
305
306 /* ------------------------------------------------- */
307 void MailHeaderFieldCleanUp(Mail_Header_FieldPtr p) {
/* [<][>][^][v][top][bottom][index][help] */
308 Mail_Header_FieldPtr ptmp = p, prev;
309
310 while (ptmp != NULL) {
311 prev = ptmp;
312 ptmp = ptmp->next;
313 if (prev->field != NULL)
314 free(prev->field);
315 free(prev);
316 }
317 }
318
319
320 /* ------------------------------------------------- */
321
322 /* Deallocate parsing tree and remove files */
323
324 void EP_MailDescrCleanUp(const EP_Mail_DescrPtr ptr) {
/* [<][>][^][v][top][bottom][index][help] */
325
326 if (ptr != NULL) {
327
328 MailHeaderFieldCleanUp(ptr->from);
329 MailHeaderFieldCleanUp(ptr->subject);
330 MailHeaderFieldCleanUp(ptr->date);
331 MailHeaderFieldCleanUp(ptr->message_id);
332 MailHeaderFieldCleanUp(ptr->reply_to);
333 MailHeaderFieldCleanUp(ptr->cc);
334 MailHeaderFieldCleanUp(ptr->content_type);
335
336 EP_TreeCleanUp(ptr->tree);
337 free(ptr);
338 }
339 }
340
341 /* ------------------------------------------------- */
342 /* Build a node filename */
343
344 void EP_BuildFilename(const EPNodePtr ptr) {
/* [<][>][^][v][top][bottom][index][help] */
345 char file[FILENAME_LENGTH];
346
347 sprintf(file, "%s%d", EP_outputPrefix, ptr->nodeID);
348 ptr->file = strdup(file);
349 }
350
351 /* ------------------------------------------------- */
352
353 void EP_ShowTree(const EPNodePtr p) {
/* [<][>][^][v][top][bottom][index][help] */
354 if (p != NULL) {
355 /* if (EP_HasContent(p)) { */
356 printf("Node ID: %d\n", p->nodeID);
357 printf("isValidPGPSignature: %s\n", vS_strRC[p->isValidPGPSignature]);
358 printf("MIMEContentType: %d\n", p->MIMEContentType);
359 printf("Key ID: %0X\n", p->keyID);
360 printf("file: %s\n\n\n", p->file);
361 /* } */
362 if (p->inner != NULL)
363 EP_ShowTree(p->inner);
364 if (p->next != NULL)
365 EP_ShowTree(p->next);
366 }
367 }
368
369 /* ------------------------------------------------- */
370
371 EPTokenPtr EP_DefineNewToken( const t_MM_type MIMEContentType,
/* [<][>][^][v][top][bottom][index][help] */
372 const char *file,
373 const EPTokenKeysPtr keysList ) {
374 EPTokenPtr token;
375 EPTokenKeysPtr head = NULL, p = keysList, pnew, prev = NULL;
376
377 token = (EPTokenPtr) UT_malloc(sizeof(EPToken));
378 token->file = (char*)file;
379 token->MIMEContentType = MIMEContentType;
380
381
382 /* generate head, and build the key list for this result node */
383 if (p != NULL) {
384 pnew = (EPTokenKeysPtr) UT_malloc(sizeof(EPTokenKeys));
385 pnew->isValidPGPSignature = p->isValidPGPSignature;
386 pnew->keyID = p->keyID;
387 pnew->next = NULL;
388 head = prev = pnew;
389 p = p->next;
390 }
391
392 while (p != NULL) {
393 pnew = (EPTokenKeysPtr) UT_malloc(sizeof(EPTokenKeys));
394 pnew->isValidPGPSignature = p->isValidPGPSignature;
395 pnew->keyID = p->keyID;
396 pnew->next = NULL;
397 prev->next = pnew;
398 prev = pnew;
399 p = p->next;
400 }
401
402 token->keys = head;
403 token->next = token->prev = NULL;
404
405 return token;
406 }
407
408 /* ------------------------------------------------- */
409
410 EPTokenKeysPtr AddKeyInfo( EPTokenKeysPtr keysList, const EPNodePtr p ){
/* [<][>][^][v][top][bottom][index][help] */
411 EPTokenKeysPtr ptk;
412
413 ptk = (EPTokenKeysPtr) UT_malloc(sizeof(EPTokenKeys));
414 ptk->isValidPGPSignature = p->isValidPGPSignature;
415 ptk->keyID = p->keyID;
416 ptk->next = NULL;
417 if (keysList == NULL)
418 return ptk;
419 else {
420 ptk->next = keysList;
421 return ptk;
422 }
423 }
424
425 /* ------------------------------------------------- */
426
427 EPTokenKeysPtr RemoveKeyInfo( const EPTokenKeysPtr keysHead ) {
/* [<][>][^][v][top][bottom][index][help] */
428 EPTokenKeysPtr tmp = keysHead->next;
429
430 free(keysHead);
431 return tmp;
432 }
433
434 /* ------------------------------------------------- */
435
436 /*
437 ep_GetPasswords: collects all passwords in the current mail chunk
438 */
439 GSList* ep_GetPasswords(char *file) {
/* [<][>][^][v][top][bottom][index][help] */
440 FILE *input_file;
441 gchar line[1024];
442 GSList *password_list = NULL;
443
444 if ((input_file = fopen(file, "r")) == NULL) {
445 ER_perror(FAC_UP, UP_CANTOPEN, "Couldn't open the file %s\n", file);
446 exit(1);
447 }
448
449 while (fgets(line, 1024, input_file) != NULL) {
450 if (strncasecmp(line, "password:", 9) == 0 &&
451 strlen(line) > 9) { // 9 = strlen 'password:'
452 //printf("pwd add %s\n", g_strstrip(strdup(line + 9)));
453 password_list = g_slist_append(password_list,
454 g_strstrip(strdup(line + 9)));
455 }
456 }
457
458 fclose (input_file);
459 return password_list;
460 }
461
462 /* ------------------------------------------------- */
463
464 /*
465
466 Password transporting works as follows:
467 Current node and siblings receive passwords from parent.
468 Child nodes of the current one receive the ones that the
469 current received plus the ones specified on the current.
470 */
471 EPTokenPtr EP_GetTokens(const EPNodePtr p, const EPTokenPtr head,
/* [<][>][^][v][top][bottom][index][help] */
472 EPTokenKeysPtr keysList, GSList *passwords) {
473 EPTokenPtr pt, ptmp = head;
474 EPTokenKeysPtr kl = keysList;
475 GSList *node_passwords = NULL;
476
477 if (p != NULL) {
478 if (p->isValidPGPSignature != vS_IS_NOT_PGP ) {
479 kl = AddKeyInfo(kl, p);
480 }
481 if (EP_HasContent(p)) {
482 pt = EP_DefineNewToken(p->MIMEContentType, p->file, kl);
483 pt->passwords = passwords;
484 if (ptmp != NULL) {
485 pt->next = ptmp;
486 ptmp->prev = pt;
487 ptmp = pt;
488 } else
489 ptmp = pt;
490 }
491 else {
492 if (p->MIMEContentType<3) { //UGLY
493 node_passwords = ep_GetPasswords(p->file);
494 node_passwords = g_slist_concat(node_passwords, passwords);
495 }
496
497 ptmp = EP_GetTokens(p->inner, ptmp, kl, node_passwords);
498 }
499
500 if (p->isValidPGPSignature != vS_IS_NOT_PGP ) {
501 kl = RemoveKeyInfo(kl);
502 }
503
504 ptmp = EP_GetTokens(p->next, ptmp, kl, passwords);
505 }
506 return ptmp;
507 }
508
509 /* ------------------------------------------------- */
510 void EP_PrintTokens(EPTokenPtr head) {
/* [<][>][^][v][top][bottom][index][help] */
511 EPTokenPtr p = head;
512 EPTokenKeysPtr ptk;
513
514 while (p != NULL) {
515 printf("Token: %s, MIMEtype: %d\n", p->file, p->MIMEContentType);
516 ptk = p->keys;
517 while (ptk != NULL) {
518 printf(" key: %0X, isValid: %s\n",
519 ptk->keyID, vS_strRC[ptk->isValidPGPSignature]);
520 ptk = ptk->next;
521 }
522 p = p->next;
523 }
524 }
525
526 /* ------------------------------------------------- */
527
528
529 void EP_CleanTokens(const EPTokenPtr head) {
/* [<][>][^][v][top][bottom][index][help] */
530 EPTokenPtr prevp, p = head;
531 EPTokenKeysPtr ptk, prevptk;
532
533 while (p != NULL) {
534 ptk = p->keys;
535 while (ptk != NULL) {
536 prevptk = ptk;
537 ptk = ptk->next;
538 free(prevptk);
539 }
540 prevp = p;
541 p = p->next;
542 free(prevp);
543 }
544 }
545
546