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