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