modules/mm/mm.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- MM_store
- MM_get_msg_headers
- MM_extract_mime
- is_supported_MIMEtype
- dispatch_to_driver
- parse_text_plain
- parse_message_rfc822
- parse_multipart_alternative
- parse_multipart_signed
- status
- get_mail_hdr_field
- get_header_line
- write_file
- read_file
- put_in_file
- do_regex_test
- mm_searched
- mm_exists
- mm_expunged
- mm_flags
- mm_notify
- mm_list
- mm_lsub
- mm_status
- mm_log
- mm_dlog
- mm_login
- mm_critical
- mm_nocritical
- mm_diskerror
- mm_fatal
1 /***************************************
2 $Revision: 2.22 $
3
4 mm - MIME Parser module. Functions to parse a mail message part,
5 find if it is MIME-encapsulated, dispatch the part to the
6 appropriate drivers (also included) and return tree nodes
7 with all MIME information.
8
9 Status: COMPLETE, NOT REVUED, TESTED
10
11 Design and implementation by: daniele@ripe.net
12
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 /* Pieces of this code stolen and/or adapted from mtest.c,
35 * part of the IMAP toolkit by Mark Crispin:
36 */
37
38 /* Original version Copyright 1988 by The Leland Stanford Junior University
39 * Copyright 1999 by the University of Washington
40 *
41 * Permission to use, copy, modify, and distribute this software and its
42 * documentation for any purpose and without fee is hereby granted, provided
43 * that the above copyright notices appear in all copies and that both the
44 * above copyright notices and this permission notice appear in supporting
45 * documentation, and that the name of the University of Washington or The
46 * Leland Stanford Junior University not be used in advertising or publicity
47 * pertaining to distribution of the software without specific, written prior
48 * permission. This software is made available "as is", and
49 * THE UNIVERSITY OF WASHINGTON AND THE LELAND STANFORD JUNIOR UNIVERSITY
50 * DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE,
51 * INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
52 * FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE UNIVERSITY OF
53 * WASHINGTON OR THE LELAND STANFORD JUNIOR UNIVERSITY BE LIABLE FOR ANY
54 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
55 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
56 * CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF
57 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
58 *
59 */
60
61
62
63 /**************************
64
65
66 "Every program attempts to expand until it can read mail.
67 Those programs which cannot so expand are replaced by
68 ones which can."
69 (Jamie Zawinski)
70
71
72 **************************/
73
74
75
76 /* Standard headers */
77 #include <stdio.h>
78 #include <signal.h>
79 #include <string.h>
80 #include <sys/time.h>
81 #include <sys/types.h>
82 /* #include <sys/param.h> */
83 #include <netdb.h>
84 #include <regex.h>
85 #include <unistd.h>
86
87
88
89 /* This is the local header */
90 #include "mm.h"
91
92 /* Other RIP headers */
93 #include "erroutines.h"
94
95
96 /*
97 * Globals to store shared data for tree nodes
98 * These variables come from EP
99 */
100
101 extern char EP_outputPrefix[FILENAME_LENGTH];
102 extern char EP_keyRing[FILENAME_LENGTH];
103 extern int EP_TreeHeight;
104 extern int EP_Node_ID;
105
106 /* Global variables to be used in this module */
107 long debug = DEFAULT_DEBUG;
108
109 char *supported_MIME_types[MAXSUPPTYPES] = {
110 "UNKNOWN/UNKNOWN", "TEXT/PLAIN", "APPLICATION/PGP", "MULTIPART/SIGNED",
111 "MULTIPART/MIXED", "MULTIPART/ALTERNATIVE", "MULTIPART/DIGEST",
112 "MESSAGE/RFC822"
113 };
114
115 long pass = 0;
116
117
118 /*
119 FIXMEs:
120 - Revise the whole debug system, debug messages etc. - right now
121 an enormous and globally useless quantity of information is dumped.
122 */
123
124
125 /*+++++++++++++++++++++++++++++++++++++++
126
127 API functions
128
129 +++++++++++++++++++++++++++++++++++++++*/
130
131
132
133 /*++++++++++
134 *
135 * MM_store(). Stores a file (or stdin) in another file,
136 * "escaping" the lines starting with "From " by adding
137 * a ">" sign. This is necessary because we need to deal
138 * with files that are "unix mailboxes".
139 *
140 * This function puts a limit to the line size that a mail
141 * message may have; officially, there is no limit to this size,
142 * but we prefer to add this limit to avoid buffer overflow.
143 * The line size limit is MAXBUFSIZE, defined in mm.h .
144 *
145 ++++++++++*/
146
147
148 int MM_store (char *source_file, char *destination_file, long custom_debug)
/* [<][>][^][v][top][bottom][index][help] */
149 {
150
151
152 /* The regexp we will be looking for */
153 #define REGEXP "^From "
154
155
156 char line[MAXBUFSIZE];
157 FILE *ifp;
158 FILE *ofp;
159 FILE *actualfile; /* Actual "file" to be opened (can be stdin) */
160 char *tmpstr;
161 short using_file = 0;
162 long numlines = 0;
163 time_t ti = time (0);
164
165
166
167 if (custom_debug)
168 debug = custom_debug;
169
170 /* Check if we need to parse a file or stdin.
171 * We parse stdin if source_file is "-" .
172 */
173
174 if (strcmp(source_file,"-"))
175 {
176 if ((ifp = fopen(source_file,"r")) != NULL)
177 {
178 ER_dbg_va (FAC_MM, ASP_MM_GEN, "MM_store: input file %s",source_file);
179 actualfile = ifp;
180 using_file = 1;
181 }
182 else
183 {
184 /* XXX Use perror to state reason? */
185 ER_perror(FAC_MM, MM_CANTOPEN, "%s for reading", source_file);
186 die;
187 }
188 }
189 else
190 {
191 ER_dbg_va (FAC_MM, ASP_MM_GEN, "MM_store: input from stdin");
192 actualfile = stdin;
193 }
194
195 if ((ofp = fopen(destination_file,"w")) != NULL)
196 {
197 while ((tmpstr = fgets(line, MAXBUFSIZE, actualfile)) != NULL)
198 {
199 numlines++;
200 if (strlen(line) >= MAXBUFSIZE - 1)
201 {
202 ER_perror(FAC_MM, MM_LINETOOLONG, "%ld",numlines);
203 die;
204 }
205 if (numlines == 1)
206 {
207 /* If the first line is not a "^From " line, put a fake one */
208 if (!do_regex_test(REGEXP,(char *)line))
209 fprintf (ofp,"From dbase@whois.ripe.net %s",ctime (&ti));
210 fputs (line,ofp);
211 }
212 else
213 {
214 if (do_regex_test(REGEXP,(char *)line)) fprintf (ofp,">");
215 fputs (line,ofp);
216 }
217 }
218 fclose(ofp);
219 if (using_file) fclose(ifp);
220 return(0);
221 }
222 else
223 {
224 /* XXX Use perror to state reason? */
225 ER_perror(FAC_MM, MM_CANTOPEN, "%s for writing", destination_file);
226 die;
227 }
228
229 /* Even though we should never get here... */
230 return(0);
231
232 } /* MM_store() */
233
234
235
236 /**********
237 *
238 * MM_get_msg_headers(). Get the headers of a mail contained in a file.
239 *
240 **********/
241
242 int MM_get_msg_headers(
/* [<][>][^][v][top][bottom][index][help] */
243 const char *mail_file, /* Input mail file */
244 EP_Mail_Descr *mail_descr, /* Structure containing the headers */
245 long mesgno, /* msg number in the input file */
246 long custom_debug /* debug level */
247 )
248 {
249 MAILSTREAM *stream = NULL; /* MAILSTREAM is defined in c-client */
250 char tmp[MAILTMPLEN]; /* MAILTMPLEN is set in c-client */
251 int retcode; /* return code of the subroutine */
252 STRINGLIST *lines; /* STRINGLIST is defined in c-client */
253 STRINGLIST *cur;
254 BODY *body;
255
256 #include "linkage.c" /* c-client requires it to be included... */
257
258
259 /* If the supplied debug level is not null, then the global debug level
260 * takes that value
261 */
262 if (custom_debug)
263 debug = custom_debug;
264
265
266 /* open mailbox and get the mail stream */
267 sprintf (tmp, "%s", mail_file);
268 stream = mail_open (stream,tmp,debug ? OP_DEBUG : NIL);
269
270 /* Process the stream */
271 if (!stream)
272 {
273 ER_perror(FAC_MM, MM_INVMBX, "%s", mail_file);
274 die;
275 }
276 else
277 {
278 ER_inf_va (FAC_MM, ASP_MM_GEN, "Getting message headers.");
279 ER_dbg_va (FAC_MM, ASP_MM_GEN, "Message status:");
280 status (stream); /* report message status */
281 ER_dbg_va (FAC_MM, ASP_MM_GEN, "End of message status.");
282
283 /* Get the headers */
284
285 lines = mail_newstringlist ();
286 cur = lines;
287
288 /* Get information about the mentioned lines in the header */
289
290
291 mail_descr->from = get_mail_hdr_field(stream, mesgno, cur, "From");
292
293 mail_descr->subject = get_mail_hdr_field(stream, mesgno, cur, "Subject");
294
295 mail_descr->date = get_mail_hdr_field(stream, mesgno, cur, "Date");
296
297 mail_descr->message_id = get_mail_hdr_field(stream, mesgno, cur, "Message-Id");
298
299 mail_descr->reply_to = get_mail_hdr_field(stream, mesgno, cur, "Reply-To");
300
301 mail_descr->cc = get_mail_hdr_field(stream, mesgno, cur, "Cc");
302
303
304
305 mail_descr->content_type = (Mail_Header_Field *)malloc(sizeof(Mail_Header_Field));
306 /* This gets all the line (with encoding etc.) */
307 /* mail_descr->content_type = get_mail_hdr_field(stream,mesgno,cur,"Content-Type"); */
308
309 /* This only gets the content-type itself in canonized form: */
310 mail_fetchstructure(stream,mesgno,&body);
311 if (body)
312 {
313 mail_descr->content_type->field = (char *)malloc(STR_M);
314 mail_descr->content_type->next = NULL;
315 sprintf(mail_descr->content_type->field,"%s",body_types[body->type]);
316 if (body->subtype)
317 sprintf(mail_descr->content_type->field+strlen(mail_descr->content_type->field),"/%s",body->subtype);
318 sprintf(mail_descr->content_type->field+strlen(mail_descr->content_type->field),"\n\n");
319 }
320
321 mail_free_stringlist (&lines);
322
323 ER_inf_va (FAC_MM, ASP_MM_GEN, "Got message headers.");
324
325
326
327 mail_close(stream);
328
329 retcode = 0;
330
331
332 }
333
334
335 return(retcode);
336
337 } /* MM_get_msg_headers() */
338
339
340
341 /*
342 * MM_extract_mime(): extract MIME information
343 * This function was inspired by display_body() in mtest.c,
344 * in the IMAP distribution. It has been largely re-engineered
345 * to support MIME, and be modular.
346 * It now only acts as an initializer of the mail stream,
347 * sending then the stream to be dispatched to the appropriate
348 * MIME drivers.
349 */
350
351
352
353
354 int MM_extract_mime (
/* [<][>][^][v][top][bottom][index][help] */
355 const char *sourcefile, /* Input file containing the mail */
356 char *pfx, /* "prefix": this can be NULL at the
357 * first call of the function */
358 EP_mail_node *mailnode, /* initialized node where to stock info */
359 long custom_debug /* debug level */
360 )
361 {
362
363 MAILSTREAM *stream = NULL; /* MAILSTREAM is defined in c-client */
364 BODY *body; /* BODY is defined in c-client */
365 char tmp[MAILTMPLEN]; /* MAILTMPLEN is set in c-client */
366 int retcode = 0; /* return code of the subroutine */
367 long mesgno = 1;
368
369
370 #include "linkage.c" /* c-client requires it to be included... */
371
372 /*
373 * This (global) variable counts the number of times we pass through
374 * MM_extract_mime().
375 * It is useful in generating unique temporary files (see below).
376 */
377
378 pass++;
379 ER_inf_va (FAC_MM, ASP_MM_GEN, "MM_extract_mime, pass %ld",pass);
380
381 if (custom_debug)
382 debug = custom_debug;
383
384 /* ER_dbg_va (FAC_MM, ASP_MM_GEN, " EP_outputPrefix: %s",EP_outputPrefix);
385 ER_dbg_va (FAC_MM, ASP_MM_GEN, " EP_keyRing: %s",EP_keyRing); */
386
387
388 /* open file and get the mail stream from there*/
389
390 sprintf (tmp, "%s", sourcefile);
391
392 stream = mail_open (stream,tmp,debug ? OP_DEBUG : NIL);
393
394 /* Process the stream */
395 if (!stream)
396 {
397 ER_perror(FAC_MM, MM_INVMBX, "%s", sourcefile);
398 die;
399 }
400 else
401 {
402 if (debug >=2)
403 {
404 ER_inf_va (FAC_MM, ASP_MM_GEN, "Getting message headers.");
405 ER_dbg_va (FAC_MM, ASP_MM_GEN, "Message status:");
406 status (stream); /* report message status */
407 ER_dbg_va (FAC_MM, ASP_MM_GEN, "End of message status.");
408 }
409 if (debug >= 2)
410 ER_dbg_va (FAC_MM, ASP_MM_GEN, "Calling mail_fetchstructure...");
411 mail_fetchstructure (stream,mesgno,&body);
412
413 if (body)
414 {
415 ER_dbg_va (FAC_MM, ASP_MM_GEN, "Got body, dispatching to drivers...");
416 dispatch_to_driver(stream, body, pfx, mailnode);
417 }
418
419 }
420
421 mail_close(stream);
422
423 return(retcode);
424
425 } /* MM_extract_mime() */
426
427
428
429 /*********************************************/
430
431 /***************************************
432 *
433 * End of API functions
434 *
435 ***************************************/
436
437
438
439 /* Internal functions */
440
441 t_MM_type is_supported_MIMEtype (BODY *body)
/* [<][>][^][v][top][bottom][index][help] */
442 {
443
444 char *mimetype_string;
445 char tmpstr[STR_S];
446 char *tmptype = tmpstr;
447 int i;
448 t_MM_type mtypecode = 0;
449
450
451 /* mimetype_string is the MIME type of the message */
452 mimetype_string = (char *)malloc(STR_S);
453 sprintf (mimetype_string,"%s",body_types[body->type]);
454 if (body->subtype)
455 sprintf (mimetype_string + strlen(mimetype_string),"/%s",body->subtype);
456
457 /*
458 * We cycle to compare the MIME type of the message
459 * to each of the MIME types we support
460 */
461 i = 0;
462 tmptype = supported_MIME_types[i];
463
464 while ((i < MAXSUPPTYPES) && (tmptype))
465 {
466 if (!strcmp(tmptype,mimetype_string))
467 {
468 mtypecode = i;
469 break;
470 }
471 tmptype = supported_MIME_types[++i];
472 }
473
474 free(mimetype_string);
475
476 return(mtypecode);
477
478 } /* is_supported_MIMEtype() */
479
480
481
482 /****
483 *
484 * dispatch_to_driver()
485 * This function dispatches a message to the proper driver
486 * which will parse it, following the MIME type
487 *
488 ****/
489
490 void dispatch_to_driver(MAILSTREAM *stream, BODY *body, char *pfx, EP_mail_node *mailnode)
/* [<][>][^][v][top][bottom][index][help] */
491 {
492
493 t_MM_type is_supported;
494
495 is_supported = is_supported_MIMEtype(body);
496 /* We assign the given MIME Type to the node */
497 mailnode->MIMEContentType = is_supported;
498
499
500 ER_dbg_va (FAC_MM, ASP_MM_GEN, " mailnode->MIMEContentType: %s",supported_MIME_types[mailnode->MIMEContentType]);
501
502 if (!strcmp(supported_MIME_types[is_supported],"TEXT/PLAIN"))
503 {
504 parse_text_plain(stream, body, pfx, mailnode);
505 }
506 else if (!strcmp(supported_MIME_types[is_supported],"APPLICATION/PGP"))
507 {
508 parse_application_pgp(stream, body, pfx, mailnode);
509 }
510 else if (!strcmp(supported_MIME_types[is_supported],"MULTIPART/ALTERNATIVE"))
511 {
512 parse_multipart_alternative(stream, body, pfx, mailnode);
513 }
514 else if (!strcmp(supported_MIME_types[is_supported],"MULTIPART/MIXED"))
515 {
516 parse_multipart_mixed(stream, body, pfx, mailnode);
517 }
518 else if (!strcmp(supported_MIME_types[is_supported],"MULTIPART/SIGNED"))
519 {
520 parse_multipart_signed(stream, body, pfx, mailnode);
521 }
522 else if (!strcmp(supported_MIME_types[is_supported],"MULTIPART/DIGEST"))
523 {
524 parse_multipart_digest(stream, body, pfx, mailnode);
525 }
526 else if (!strcmp(supported_MIME_types[is_supported],"MESSAGE/RFC822"))
527 {
528 parse_message_rfc822(stream, body, pfx, mailnode);
529 }
530 else
531 {
532 /* It's not a supported MIMEtype... */
533 parse_unknown_unknown(stream, body, pfx, mailnode);
534 }
535
536 } /* dispatch_to_driver() */
537
538
539 void parse_text_plain(MAILSTREAM *stream, BODY *body, char *pfx, EP_mail_node *mailnode)
/* [<][>][^][v][top][bottom][index][help] */
540 {
541
542 char tmp[MAILTMPLEN];
543 char *mailtext;
544
545
546 if (debug >= 2)
547 ER_dbg_va (FAC_MM, ASP_MM_GEN, " Lines: %lu",body->size.lines);
548
549 if (pfx == NULL) /* If top level, is not inside a multipart */
550 {
551 if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "MAILNODE->FILE: %s",mailnode->file);
552 /* The filename of the root node has to be redefined to the processed file */
553 remove(mailnode->file);
554 free(mailnode->file);
555 mailnode->file = (char *)malloc(FILENAME_LENGTH);
556 sprintf(mailnode->file,"%s%d",EP_outputPrefix,mailnode->nodeID);
557 if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "MAILNODE->FILE: %s",mailnode->file);
558 }
559 else
560
561 ER_dbg_va (FAC_MM, ASP_MM_GEN, " mailnode->file: %s",mailnode->file);
562
563 /* Get the plain text contents of the message */
564 mailtext = tmp;
565 mailtext = mail_fetchtext(stream, 1);
566
567 if (debug >= 2)
568 {
569 ER_dbg_va (FAC_MM, ASP_MM_GEN, "Message contents:");
570 ER_dbg_va (FAC_MM, ASP_MM_GEN, "\n\n%s\n",mailtext);
571 }
572
573
574 /* Place the results in the file pointed by the node*/
575 write_file(mailnode->file,mailtext,strlen(mailtext));
576
577 PA_ParseMessage(mailnode);
578
579 /* if (debug) printf ("mailnode->nodeID: %d\n",mailnode->nodeID); */
580 /* if (debug) printf ("mailnode->MIMEContentType: %d\n",mailnode->MIMEContentType); */
581
582 }
583
584 void parse_message_rfc822(MAILSTREAM *stream, BODY *body, char *pfx, EP_mail_node *mailnode)
/* [<][>][^][v][top][bottom][index][help] */
585 {
586
587 /* The idea here is to strip the message/rfc822 part from its mail headers,
588 * and store it in a file to resend to MM_extract_mime().
589 */
590
591 char tmp[MAILTMPLEN];
592 char *mailtext;
593 char *content;
594 char tmpfile[FILENAMELEN];
595 time_t ti = time (0);
596
597
598 if (pfx == NULL) /* If top level, is not inside a multipart */
599 {
600 /* pfx = (char *)malloc(STR_L);
601 pfx = ""; */ /* Dummy prefix */
602 /* The filename of the root node has to be redefined to the processed file */
603 mailnode->file = (char *)malloc(FILENAME_LENGTH);
604 sprintf(mailnode->file,"%s%d",EP_outputPrefix,mailnode->nodeID);
605 if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "MAILNODE->FILE: %s",mailnode->file);
606 }
607
608 /* Get the plain text contents of the message */
609 mailtext = tmp;
610 mailtext = mail_fetchtext(stream, 1);
611
612
613 /* This buffer has to be dumped in a file from where it will be read by MM_extract_mime():
614 * another stream will be opened, so the format of the file must be correct.
615 * The LINELENGTH is to take the first 2 lines into account.
616 */
617
618 content = (char *)malloc(2*LINELENGTH + strlen(mailtext) + 2);
619 sprintf (content,"From dbase@whois.ripe.net %s",ctime (&ti));
620 sprintf (content+strlen(content), "%s\n", mailtext);
621
622
623 /* Generation of a temporary file:
624 * The file must be unique inside the process. If we rewrite
625 * on the same tmp file, which is used as a mailbox by c-client,
626 * the c-client library has problems because it sees the mailbox changes
627 * (I had problems with multipart/digest and message/rfc822).
628 * "pass" is a global variable which increases every time we pass
629 * through MM_extract_mime(): it should hence be unique each time
630 * we call a driver.
631 */
632 sprintf (tmpfile,"%s.tmp.%ld",mailnode->file,pass);
633 write_file(tmpfile,content,strlen(content));
634
635 MM_extract_mime(tmpfile, pfx, mailnode, debug);
636
637 /* Clean up... */
638 free(content);
639 remove(tmpfile);
640
641 }
642
643 void parse_multipart_alternative (MAILSTREAM *stream, BODY *body, char *pfx, EP_mail_node *mailnode)
/* [<][>][^][v][top][bottom][index][help] */
644 {
645
646 char tmppfx[MAILTMPLEN];
647 char childpfx[MAILTMPLEN];
648 char tmppart[MAILTMPLEN];
649 /* char *s = tmppfx; */
650 EP_mail_node *newnode;
651 EP_mail_node *parsednode;
652 EP_mail_node *nextnode;
653 long i;
654 PART *part;
655 char *result;
656 char *content;
657 unsigned long length;
658 time_t ti = time (0);
659 char tmpfile[FILENAMELEN];
660 char nodefile[FILENAMELEN];
661
662
663 if (debug >= 2)
664 ER_dbg_va (FAC_MM, ASP_MM_GEN, "Bytes: %lu",body->size.bytes);
665
666 /* if not first time, extend prefix */
667 if (pfx == NULL)
668 {
669 tmppfx[0] = '\0';
670 pfx = tmppfx;
671 }
672
673
674 /* Initialize the first node: it is an inner node */
675
676 /* The tree height increases */
677 EP_TreeHeight++;
678
679 /* The number of nodes increases */
680 EP_Node_ID++;
681
682 sprintf (nodefile,"%s%d",EP_outputPrefix,EP_Node_ID);
683 if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "inner-nodefile: %s",nodefile);
684
685 newnode = EP_InitializeNode(nodefile, EP_Node_ID);
686 mailnode->inner = newnode;
687
688 for (i = 1,part = body->nested.part; part; part = part->next)
689 {
690 if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "i: %ld, pfx: %s",i,pfx);
691 if (debug >= 3) ER_dbg_va (FAC_MM, ASP_MM_GEN, "MYDEBUG: pfx=%s, tmppfx=%s,",pfx,tmppfx);
692 sprintf (tmppart,"%ld",i);
693 result = mail_fetch_mime(stream, (long)1, tmppart, &length, (long)0);
694 if (debug >= 3)
695 {
696 ER_dbg_va (FAC_MM, ASP_MM_GEN, "body->size.bytes: %lu",body->size.bytes);
697 ER_dbg_va (FAC_MM, ASP_MM_GEN, "(&part->body)->size.bytes: %lu",(&part->body)->size.bytes);
698 ER_dbg_va (FAC_MM, ASP_MM_GEN, "length: %lu",length);
699 }
700
701
702 /* This buffer has to be dumped in a file from where it will be read by MM_extract_mime():
703 * another stream will be opened, so the format of the file must be correct.
704 * The LINELENGTH is to take the first 2 lines into account
705 */
706 content = (char *)malloc(2*LINELENGTH + length + (&part->body)->size.bytes + 2);
707 sprintf (content,"From dbase@whois.ripe.net %sMIME-Version: 1.0\n",ctime (&ti));
708 /* snprintf (content+strlen(content), (size_t)(length + (&part->body)->size.bytes) + 2, "%s\n", result); */
709 g_snprintf ((gchar *)(content+strlen(content)), (gulong)(length + (&part->body)->size.bytes) + 2, "%s\n", result);
710
711 if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "Result: \n---\n%s\n---\nEnd results.\n", content);
712
713 /* Generation of a temporary file:
714 * The file must be unique inside the process. If we rewrite
715 * on the same tmp file, which is used as a mailbox by c-client,
716 * the c-client library has problems because it sees it changes
717 * (I had problems with multipart/digest and message/rfc822).
718 * "pass" is a global variable which increases every time we pass
719 * through MM_extract_mime(): it should hence be unique each time
720 * we call a driver.
721 */
722 sprintf (tmpfile,"%s.tmp.%ld",newnode->file,pass);
723 write_file(tmpfile,content,strlen(content));
724
725 /* This is needed to extend the prefix */
726 sprintf (childpfx,"%s%ld.",pfx,i);
727 if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "childpfx: %s",childpfx);
728 MM_extract_mime(tmpfile, childpfx, newnode, debug);
729
730 /* Clean up... */
731 free(content);
732 remove(tmpfile);
733
734 /* Initialize the next node (if it exists) */
735
736 if (part->next != NULL)
737 {
738 EP_Node_ID++;
739 sprintf (nodefile,"%s%d",EP_outputPrefix,EP_Node_ID);
740 if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "next-nodefile: %s",nodefile);
741 nextnode = EP_InitializeNode(nodefile, EP_Node_ID);
742 parsednode = newnode;
743 newnode = nextnode;
744 parsednode->next = newnode;
745 }
746
747 i++;
748
749 }
750
751 } /* parse_multipart_alternative() */
752
753
754 void parse_multipart_signed (MAILSTREAM *stream, BODY *body, char *pfx, EP_mail_node *mailnode)
/* [<][>][^][v][top][bottom][index][help] */
755 {
756
757 char tmppfx[MAILTMPLEN];
758 char tmppart[MAILTMPLEN];
759 EP_mail_node *newnode;
760 PART *part;
761 char *result;
762 char *content;
763 unsigned long length;
764 char tmpfile[FILENAMELEN];
765 char nodefile[FILENAMELEN];
766 struct VerifySignObject vSO;
767 /* int retcode; */
768
769 if (debug >= 2)
770 ER_dbg_va (FAC_MM, ASP_MM_GEN, "Bytes: %lu",body->size.bytes);
771
772
773 /* if not first time, extend prefix */
774 if (pfx == NULL)
775 {
776 tmppfx[0] = '\0';
777 pfx = tmppfx;
778 }
779
780
781 /* Initialize the inner node */
782
783 /* The tree height increases */
784 EP_TreeHeight++;
785
786 /* The number of nodes increases */
787 EP_Node_ID++;
788
789 sprintf (nodefile,"%s%d",EP_outputPrefix,EP_Node_ID);
790 if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "inner-nodefile: %s",nodefile);
791
792 newnode = EP_InitializeNode(nodefile, EP_Node_ID);
793 mailnode->inner = newnode;
794
795 /* We give the same content-type to the child so as not to leave the default
796 value (-1) */
797 newnode->MIMEContentType = mailnode->MIMEContentType;
798
799 /* We must get the two parts of the message. The signed part
800 * and the signature. There can't be more than two parts
801 * (see RFC2015).
802 */
803
804 if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "pfx: %s",pfx);
805
806 /* Signed part: it is the first part of the message. */
807
808 part = body->nested.part;
809
810 sprintf (tmppart,"%s1",tmppfx);
811 if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "tmppart: %s",tmppart);
812
813 result = mail_fetch_mime(stream, (long)1, tmppart, &length, (long)0);
814 if (debug >= 3)
815 {
816 ER_dbg_va (FAC_MM, ASP_MM_GEN, "body->size.bytes: %lu",body->size.bytes);
817 ER_dbg_va (FAC_MM, ASP_MM_GEN, "(&part->body)->size.bytes: %lu",(&part->body)->size.bytes);
818 ER_dbg_va (FAC_MM, ASP_MM_GEN, "length: %lu",length);
819 }
820
821 /* The signed part must be dumped in a file together with the MIME headers */
822
823 content = (char *)malloc(length + (&part->body)->size.bytes + 2);
824 snprintf (content,(size_t)(length + (&part->body)->size.bytes) + 2, "%s\n", result);
825
826 if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "Result: \n---\n%s\n---\nEnd results.\n", content);
827
828 if (debug) ER_dbg_va (FAC_MM, ASP_MM_GEN, "MSG file: %s",newnode->file);
829 write_file(newnode->file,content,strlen(content));
830
831
832 free(content);
833
834 /* Signature */
835
836 part = part->next;
837 sprintf (tmppart,"%s2",tmppfx);
838 if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "tmppart: %s",tmppart);
839
840 result = mail_fetch_mime(stream, (long)1, tmppart, &length, (long)0);
841 if (debug >= 2)
842 {
843 ER_dbg_va (FAC_MM, ASP_MM_GEN, "body->size.bytes: %lu\n",body->size.bytes);
844 ER_dbg_va (FAC_MM, ASP_MM_GEN, "(&part->body)->size.bytes: %lu\n",(&part->body)->size.bytes);
845 ER_dbg_va (FAC_MM, ASP_MM_GEN, "length: %lu\n",length);
846 }
847
848 /* The signature must be dumped _without_ MIME headers instead!
849 * Check where is the "length" variable...
850 */
851
852 content = (char *)malloc((&part->body)->size.bytes + 2);
853
854 snprintf (content,(size_t)((&part->body)->size.bytes) + 2, "%s\n", result + length);
855
856 if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "Result: \n---\n%s\n---\nEnd results.\n", content);
857
858 sprintf (tmpfile,"%s.sig",newnode->file);
859 if (debug) ER_dbg_va (FAC_MM, ASP_MM_GEN, "SIG file: %s",tmpfile);
860 write_file(tmpfile,content,strlen(content));
861
862 /* Calling the verification procedure */
863
864 strcpy(vSO.iDocSigFilename, newnode->file);
865 strcpy(vSO.iSigFilename, tmpfile);
866 strcpy(vSO.keyRing, EP_keyRing);
867
868 PA_VerifySignature(&vSO);
869
870 newnode->isValidPGPSignature = vSO.isValid;
871 newnode->keyID= vSO.keyID;
872
873 EP_MIMEParse(newnode);
874
875 free(content);
876 remove(tmpfile);
877
878
879 } /* parse_multipart_signed */
880
881
882
883 /* MM status report
884 * Accepts: MAIL stream
885 */
886
887 void status (MAILSTREAM *stream)
/* [<][>][^][v][top][bottom][index][help] */
888 {
889 long i;
890 char date[MAILTMPLEN];
891 rfc822_date (date);
892 ER_dbg_va (FAC_MM, ASP_MM_GEN, "%s",date);
893 if (stream)
894 {
895 if (stream->mailbox)
896 {
897 ER_dbg_va (FAC_MM, ASP_MM_GEN, " %s mailbox: %s",
898 stream->dtb->name,stream->mailbox);
899 ER_dbg_va (FAC_MM, ASP_MM_GEN, " %lu messages, %lu recent",
900 stream->nmsgs,stream->recent);
901 }
902 else ER_dbg_va (FAC_MM, ASP_MM_GEN, "% No mailbox is open on this stream");
903 if (stream->user_flags[0])
904 {
905 ER_dbg_va (FAC_MM, ASP_MM_GEN, "Keywords: %s",stream->user_flags[0]);
906 for (i = 1; i < NUSERFLAGS && stream->user_flags[i]; ++i)
907 ER_dbg_va (FAC_MM, ASP_MM_GEN,", %s",stream->user_flags[i]);
908 /* puts (""); */
909 }
910 }
911 } /* status() */
912
913
914 Mail_Header_Field *get_mail_hdr_field (MAILSTREAM *stream,
/* [<][>][^][v][top][bottom][index][help] */
915 long mesgno,
916 STRINGLIST *cur,
917 const char *hdr_title)
918 {
919
920 char *tmphdr;
921 char tmpline[MAXBUFSIZE];
922 int i, j, c, tmpsize, titlesize;
923 Mail_Header_Field *hdr_field;
924 Mail_Header_Field *mhfp;
925 Mail_Header_Field *newmhfp;
926
927 mhfp = hdr_field = newmhfp = NULL;
928
929 tmphdr = get_header_line(stream,mesgno,cur,hdr_title);
930
931 tmpsize = strlen(tmphdr);
932
933 /* Length of the header title plus ": "*/
934 titlesize = strlen(hdr_title) + 2;
935
936 j = 0;
937
938 /* Get one line at a time, and put the header lines in the Mail Header Field */
939
940 for (i = 0; i < tmpsize; i++)
941 {
942 c = tmphdr[i];
943 if (c == 10) /* EOL */
944 {
945 if ((j > 1) || ((mhfp == NULL) && (i == tmpsize - 1))) /* j>1 and not j>0 because "\r" is always read;
946 * The second option is needed for
947 * the empty headers */
948 {
949 newmhfp = (Mail_Header_Field *)malloc(sizeof(Mail_Header_Field));
950 newmhfp->next = NULL;
951 newmhfp->field = (char *)malloc(j + 2);
952 if (j > 1)
953 /* We do not copy here the header title */
954 sprintf (newmhfp->field,"%s\n",tmpline + titlesize);
955 else
956 sprintf (newmhfp->field,"\n");
957
958
959 if (mhfp == NULL)
960 {
961 mhfp = newmhfp;
962 hdr_field = newmhfp;
963 }
964 else
965 {
966 mhfp->next = newmhfp;
967 mhfp = newmhfp;
968 }
969 }
970 j = 0;
971 }
972 else
973 {
974 sprintf (tmpline + j++,"%c", c);
975 }
976
977 }
978
979 free(tmphdr);
980
981 return (hdr_field);
982
983 } /* get_mail_hdr_field() */
984
985
986
987 char *get_header_line (MAILSTREAM *stream, long mesgno, STRINGLIST *cur, const char *hdr_title)
/* [<][>][^][v][top][bottom][index][help] */
988 {
989
990 unsigned long offset;
991 size_t tmplength;
992 char *curtmp;
993 char *hdr_attr;
994 long a,b;
995
996
997 /* We need to insert the header title into a STRINGLIST structure, as
998 * this is the type that must be supplied to mail_fetchheader_full.
999 */
1000
1001 cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
1002 cpystr (hdr_title)));
1003
1004 /* If we don't want to return the header title, but only the contents,
1005 * this offset allows us to strip the header title. The "magic number" 2
1006 * is the string ": " of the header.
1007 * This method is uneffective for multiple headers (ex. Cc, Reply-To, etc.).
1008 */
1009
1010 offset = cur->text.size + 2;
1011
1012 /* Get the header line, if it exists */
1013
1014 curtmp = mail_fetchheader_full (stream,mesgno,cur,NIL,NIL);
1015
1016 tmplength = strlen(curtmp);
1017 hdr_attr = (char *)malloc(tmplength + 4);
1018
1019 /* cur contains the header title string, like "From:", "Subject:" etc.
1020 * tmplength is the length of the corresponding header line extracted
1021 * from the message. If a real line is returned, the header title
1022 * ("From:", "Subject:" etc.) will be contained within, hence
1023 * tmplength >= cur->text.size . This means that if
1024 * (cur->text.size > tmplength), no such header is present in the mail:
1025 * we must return an (almost) empty string.
1026 */
1027
1028 a = (long)tmplength;
1029 b = (long)cur->text.size;
1030 if (a > b)
1031 {
1032 /* If we want to strip the header */
1033 /*sprintf (hdr_attr,"%s",curtmp + offset); */
1034 sprintf (hdr_attr,"%s",curtmp);
1035 /* printf ("%s",hdr_attr); */
1036 }
1037 else
1038 {
1039 sprintf (hdr_attr,"\n\n");
1040 }
1041
1042 return (hdr_attr);
1043 } /* get_header_line() */
1044
1045
1046
1047
1048 /* Subroutine for writing in a file */
1049
1050 void write_file (char *filename, char *text, size_t text_size)
/* [<][>][^][v][top][bottom][index][help] */
1051 {
1052
1053 FILE *fd;
1054 size_t i;
1055
1056 /* printf ("%s\n",filename); */
1057
1058 if ((fd = fopen(filename,"w")) != NULL)
1059 {
1060 for (i = 0; i < text_size; i++)
1061 if (text[i] != 13)
1062 fprintf (fd, "%c",text[i]);
1063 fclose(fd);
1064 }
1065 else
1066 {
1067 ER_perror(FAC_MM, MM_CANTOPEN, "%s for writing\n",filename);
1068 die;
1069 }
1070
1071 } /* write_file() */
1072
1073
1074 void read_file (const char *filename)
/* [<][>][^][v][top][bottom][index][help] */
1075 {
1076
1077 FILE *fd;
1078 int c;
1079
1080 if ((fd = fopen (filename,"r")) != NULL)
1081 {
1082 while ((c = getc(fd)) != EOF)
1083 putc (c, stdout);
1084 fclose (fd);
1085 }
1086 else
1087 {
1088 ER_perror(FAC_MM, MM_CANTOPEN, "%s for reading\n",filename);
1089 die;
1090 }
1091
1092 } /* read_file() */
1093
1094
1095 void put_in_file (char *fileprefix, char *extension, char *text, size_t text_size)
/* [<][>][^][v][top][bottom][index][help] */
1096 {
1097
1098 char filename[FILENAMELEN];
1099
1100
1101 /* Write in a file */
1102
1103 sprintf (filename,"%s-%s",fileprefix,extension);
1104 /* printf ("%s\n",filename); */
1105
1106 write_file(filename,text,text_size);
1107
1108 }/* put_in_file() */
1109
1110
1111 /* Stolen from which_keytypes.c and converted to use regex.h instead of libgen.h */
1112
1113
1114 int do_regex_test (const char *pattern, char *string)
/* [<][>][^][v][top][bottom][index][help] */
1115 {
1116
1117 int match = 0;
1118
1119 /* These are not used, since REG_NOSUB is specified in regcomp() */
1120 size_t nmatch = 0;
1121 regmatch_t pmatch[1];
1122
1123 regex_t *re;
1124
1125 re = (regex_t *)malloc(STR_XL);
1126
1127 regcomp(re, pattern, REG_NOSUB || REG_NEWLINE);
1128 if (regexec(re, string, nmatch, pmatch, 0))
1129 match = 0;
1130 else
1131 match = 1;
1132
1133 regfree(re);
1134
1135 /* Caution! regfree() does not do this job... */
1136 free(re);
1137
1138 return(match);
1139
1140 } /* do_regex_test() */
1141
1142
1143 /* Interfaces to c-client.
1144 * They must be here for the code to be compiled,
1145 * but most can stay empty.
1146 */
1147
1148 void mm_searched (MAILSTREAM *stream,unsigned long number)
/* [<][>][^][v][top][bottom][index][help] */
1149 {
1150 }
1151
1152
1153 void mm_exists (MAILSTREAM *stream,unsigned long number)
/* [<][>][^][v][top][bottom][index][help] */
1154 {
1155 }
1156
1157
1158 void mm_expunged (MAILSTREAM *stream,unsigned long number)
/* [<][>][^][v][top][bottom][index][help] */
1159 {
1160 }
1161
1162
1163 void mm_flags (MAILSTREAM *stream,unsigned long number)
/* [<][>][^][v][top][bottom][index][help] */
1164 {
1165 }
1166
1167 void mm_notify (MAILSTREAM *stream,char *string,long errflg)
/* [<][>][^][v][top][bottom][index][help] */
1168 {
1169 }
1170
1171 void mm_list (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
/* [<][>][^][v][top][bottom][index][help] */
1172 {
1173 }
1174
1175 void mm_lsub (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
/* [<][>][^][v][top][bottom][index][help] */
1176 {
1177 }
1178
1179 void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
/* [<][>][^][v][top][bottom][index][help] */
1180 {
1181 }
1182
1183 void mm_log (char *string,long errflg)
/* [<][>][^][v][top][bottom][index][help] */
1184 {
1185 switch ((short) errflg) {
1186 case NIL:
1187 ER_dbg_va (FAC_MM, ASP_MM_GEN, "[%s]",string);
1188 break;
1189 case PARSE:
1190 case WARN:
1191 ER_perror (FAC_MM, MM_WARNCCL, "%%%s",string);
1192 break;
1193 case ERROR:
1194 ER_perror (FAC_MM, MM_ERRCCL, "%s",string);
1195 break;
1196 }
1197 }
1198
1199 void mm_dlog (char *string)
/* [<][>][^][v][top][bottom][index][help] */
1200 {
1201 puts (string);
1202 }
1203
1204 void mm_login (NETMBX *mb,char *user,char *pwd,long trial)
/* [<][>][^][v][top][bottom][index][help] */
1205 {
1206 }
1207
1208 void mm_critical (MAILSTREAM *stream)
/* [<][>][^][v][top][bottom][index][help] */
1209 {
1210 }
1211
1212 void mm_nocritical (MAILSTREAM *stream)
/* [<][>][^][v][top][bottom][index][help] */
1213 {
1214 }
1215
1216 long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
/* [<][>][^][v][top][bottom][index][help] */
1217 {
1218 #if UNIXLIKE
1219 kill (getpid (),SIGSTOP);
1220 #else
1221 abort ();
1222 #endif
1223 return NIL;
1224 }
1225
1226 void mm_fatal (char *string)
/* [<][>][^][v][top][bottom][index][help] */
1227 {
1228 ER_perror(FAC_MM, MM_FATCCL, "%s\n",string);
1229 die;
1230 }
1231