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.29 $
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,2002 RIPE NCC
15
16 All Rights Reserved
17
18 Permission to use, copy, modify, and distribute this software and its
19 documentation for any purpose and without fee is hereby granted,
20 provided that the above copyright notice appear in all copies and that
21 both that copyright notice and this permission notice appear in
22 supporting documentation, and that the name of the author not be
23 used in advertising or publicity pertaining to distribution of the
24 software without specific, written prior permission.
25
26 THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
27 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
28 AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
29 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
30 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
31 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32 ***************************************/
33
34 /* 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, k, c, tmpsize, titlesize;
925 int continuation = 0;
926 Mail_Header_Field *hdr_field;
927 Mail_Header_Field *mhfp;
928 Mail_Header_Field *newmhfp;
929
930 mhfp = hdr_field = newmhfp = NULL;
931
932 tmphdr = get_header_line(stream,mesgno,cur,hdr_title);
933
934 tmpsize = strlen(tmphdr);
935
936 /* Length of the header title plus ":" */
937 titlesize = strlen(hdr_title) + 1;
938
939 continuation = 0; /* to detect continuation lines */
940 j = 0;
941 /* also initialize tmpline */
942 for(i = 0; i < MAXBUFSIZE; i++){
943 tmpline[i] = '\0';
944 }
945
946 /* Get one line at a time, and put the header lines in the Mail Header Field */
947
948 for (i = 0; i < tmpsize; i++)
949 {
950 c = tmphdr[i];
951 if (c == 10) /* EOL */
952 {
953 if ((j > 1) || ((mhfp == NULL) && (i == tmpsize - 1))) /* j>1 and not j>0 because "\r" is always read;
954 * The second option is needed for
955 * the empty headers */
956 {
957 newmhfp = (Mail_Header_Field *)UT_malloc(sizeof(Mail_Header_Field));
958 newmhfp->next = NULL;
959 newmhfp->field = (char *)UT_malloc(j + 2);
960 if (j > 1)
961 {
962 if ( ! continuation )
963 /* We do not copy the header title from the first line */
964 sprintf (newmhfp->field,"%s\n",tmpline + titlesize);
965 else
966 /* There is no header title on continuation lines */
967 sprintf (newmhfp->field,"%s\n",tmpline);
968 }
969 else
970 sprintf (newmhfp->field,"\n");
971
972 if (mhfp == NULL)
973 {
974 mhfp = newmhfp;
975 hdr_field = newmhfp;
976 }
977 else
978 {
979 mhfp->next = newmhfp;
980 mhfp = newmhfp;
981 }
982 }
983 continuation = 1; /* next time we are reading continuation lines */
984 j = 0;
985 /* re-initialize tmpline */
986 for (k = 0; k < MAXBUFSIZE; k++)
987 {
988 tmpline[k] = '\0';
989 }
990 }
991 else
992 {
993 sprintf (tmpline + j++,"%c", c);
994 }
995 }
996
997 UT_free(tmphdr);
998
999 return (hdr_field);
1000
1001 } /* get_mail_hdr_field() */
1002
1003
1004
1005 char *get_header_line (MAILSTREAM *stream, long mesgno, STRINGLIST *cur, const char *hdr_title)
/* [<][>][^][v][top][bottom][index][help] */
1006 {
1007
1008 unsigned long offset;
1009 size_t tmplength;
1010 char *curtmp;
1011 char *hdr_attr;
1012 long a,b;
1013
1014
1015 /* We need to insert the header title into a STRINGLIST structure, as
1016 * this is the type that must be supplied to mail_fetchheader_full.
1017 */
1018
1019 cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
1020 cpystr (hdr_title)));
1021
1022 /* If we don't want to return the header title, but only the contents,
1023 * this offset allows us to strip the header title. The "magic number" 2
1024 * is the string ": " of the header.
1025 * This method is uneffective for multiple headers (ex. Cc, Reply-To, etc.).
1026 */
1027
1028 offset = cur->text.size + 2;
1029
1030 /* Get the header line, if it exists */
1031
1032 curtmp = mail_fetchheader_full (stream,mesgno,cur,NIL,NIL);
1033
1034 tmplength = strlen(curtmp);
1035 hdr_attr = (char *)UT_malloc(tmplength + 4);
1036
1037 /* cur contains the header title string, like "From:", "Subject:" etc.
1038 * tmplength is the length of the corresponding header line extracted
1039 * from the message. If a real line is returned, the header title
1040 * ("From:", "Subject:" etc.) will be contained within, hence
1041 * tmplength >= cur->text.size . This means that if
1042 * (cur->text.size > tmplength), no such header is present in the mail:
1043 * we must return an (almost) empty string.
1044 */
1045
1046 a = (long)tmplength;
1047 b = (long)cur->text.size;
1048 if (a > b)
1049 {
1050 /* If we want to strip the header */
1051 /*sprintf (hdr_attr,"%s",curtmp + offset); */
1052 sprintf (hdr_attr,"%s",curtmp);
1053 /* printf ("%s",hdr_attr); */
1054 }
1055 else
1056 {
1057 sprintf (hdr_attr,"\n\n");
1058 }
1059
1060 return (hdr_attr);
1061 } /* get_header_line() */
1062
1063
1064
1065
1066 /* Subroutine for writing in a file */
1067
1068 void write_file (char *filename, char *text, size_t text_size)
/* [<][>][^][v][top][bottom][index][help] */
1069 {
1070
1071 FILE *fd;
1072 size_t i;
1073
1074 /* printf ("%s\n",filename); */
1075
1076 if ((fd = fopen(filename,"w")) != NULL)
1077 {
1078 for (i = 0; i < text_size; i++)
1079 if (text[i] != 13)
1080 fprintf (fd, "%c",text[i]);
1081 fclose(fd);
1082 }
1083 else
1084 {
1085 ER_perror(FAC_MM, MM_CANTOPEN, "%s for writing\n",filename);
1086 die;
1087 }
1088
1089 } /* write_file() */
1090
1091
1092 void read_file (const char *filename)
/* [<][>][^][v][top][bottom][index][help] */
1093 {
1094
1095 FILE *fd;
1096 int c;
1097
1098 if ((fd = fopen (filename,"r")) != NULL)
1099 {
1100 while ((c = getc(fd)) != EOF)
1101 putc (c, stdout);
1102 fclose (fd);
1103 }
1104 else
1105 {
1106 ER_perror(FAC_MM, MM_CANTOPEN, "%s for reading\n",filename);
1107 die;
1108 }
1109
1110 } /* read_file() */
1111
1112
1113 void put_in_file (char *fileprefix, char *extension, char *text, size_t text_size)
/* [<][>][^][v][top][bottom][index][help] */
1114 {
1115
1116 char filename[FILENAMELEN];
1117
1118
1119 /* Write in a file */
1120
1121 sprintf (filename,"%s-%s",fileprefix,extension);
1122 /* printf ("%s\n",filename); */
1123
1124 write_file(filename,text,text_size);
1125
1126 }/* put_in_file() */
1127
1128
1129 /* Stolen from which_keytypes.c and converted to use regex.h instead of libgen.h */
1130
1131
1132 int do_regex_test (const char *pattern, char *string)
/* [<][>][^][v][top][bottom][index][help] */
1133 {
1134
1135 int match = 0;
1136
1137 /* These are not used, since REG_NOSUB is specified in regcomp() */
1138 size_t nmatch = 0;
1139 regmatch_t pmatch[1];
1140
1141 regex_t *re;
1142
1143 re = (regex_t *)UT_malloc(STR_XL);
1144
1145 regcomp(re, pattern, REG_NOSUB || REG_NEWLINE);
1146 if (regexec(re, string, nmatch, pmatch, 0))
1147 match = 0;
1148 else
1149 match = 1;
1150
1151 regfree(re);
1152
1153 /* Caution! regfree() does not do this job... */
1154 UT_free(re);
1155
1156 return(match);
1157
1158 } /* do_regex_test() */
1159
1160
1161 /* Interfaces to c-client.
1162 * They must be here for the code to be compiled,
1163 * but most can stay empty.
1164 */
1165
1166 void mm_searched (MAILSTREAM *stream,unsigned long number)
/* [<][>][^][v][top][bottom][index][help] */
1167 {
1168 }
1169
1170
1171 void mm_exists (MAILSTREAM *stream,unsigned long number)
/* [<][>][^][v][top][bottom][index][help] */
1172 {
1173 }
1174
1175
1176 void mm_expunged (MAILSTREAM *stream,unsigned long number)
/* [<][>][^][v][top][bottom][index][help] */
1177 {
1178 }
1179
1180
1181 void mm_flags (MAILSTREAM *stream,unsigned long number)
/* [<][>][^][v][top][bottom][index][help] */
1182 {
1183 }
1184
1185 void mm_notify (MAILSTREAM *stream,char *string,long errflg)
/* [<][>][^][v][top][bottom][index][help] */
1186 {
1187 }
1188
1189 void mm_list (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
/* [<][>][^][v][top][bottom][index][help] */
1190 {
1191 }
1192
1193 void mm_lsub (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
/* [<][>][^][v][top][bottom][index][help] */
1194 {
1195 }
1196
1197 void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
/* [<][>][^][v][top][bottom][index][help] */
1198 {
1199 }
1200
1201 void mm_log (char *string,long errflg)
/* [<][>][^][v][top][bottom][index][help] */
1202 {
1203 switch ((short) errflg) {
1204 case NIL:
1205 ER_dbg_va (FAC_MM, ASP_MM_GEN, "[%s]",string);
1206 break;
1207 case PARSE:
1208 case WARN:
1209 ER_perror (FAC_MM, MM_WARNCCL, "%%%s",string);
1210 break;
1211 case ERROR:
1212 ER_perror (FAC_MM, MM_ERRCCL, "%s",string);
1213 break;
1214 }
1215 }
1216
1217 void mm_dlog (char *string)
/* [<][>][^][v][top][bottom][index][help] */
1218 {
1219 puts (string);
1220 }
1221
1222 void mm_login (NETMBX *mb,char *user,char *pwd,long trial)
/* [<][>][^][v][top][bottom][index][help] */
1223 {
1224 }
1225
1226 void mm_critical (MAILSTREAM *stream)
/* [<][>][^][v][top][bottom][index][help] */
1227 {
1228 }
1229
1230 void mm_nocritical (MAILSTREAM *stream)
/* [<][>][^][v][top][bottom][index][help] */
1231 {
1232 }
1233
1234 long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
/* [<][>][^][v][top][bottom][index][help] */
1235 {
1236 #if UNIXLIKE
1237 kill (getpid (),SIGSTOP);
1238 #else
1239 abort ();
1240 #endif
1241 return NIL;
1242 }
1243
1244 void mm_fatal (char *string)
/* [<][>][^][v][top][bottom][index][help] */
1245 {
1246 ER_perror(FAC_MM, MM_FATCCL, "%s\n",string);
1247 die;
1248 }
1249