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