modules/mm/mm.c
/* [<][>][^][v][top][bottom][index][help] */
FUNCTIONS
This source file includes following functions.
- MM_decode
- MM_store
- MM_cleanup
- mm
- get_body_info
- status
- MM_bs_list_init
- MM_bs_list_ins_last
- MM_bs_list_cleanup
- MM_xmp_list_init
- MM_xmp_list_ins_last
- 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: 1.12 $
3
4 mm - MIME Parser module. Functions to parse a mail message,
5 find if it is MIME-encapsulated, and return the parts of
6 the message which are supported by the UP module.
7
8 Status: NOT REVUED
9
10 Design and implementation by: Daniele Arena
11
12 ******************/ /******************
13 Copyright (c) 2000 RIPE NCC
14
15 All Rights Reserved
16
17 Permission to use, copy, modify, and distribute this software and its
18 documentation for any purpose and without fee is hereby granted,
19 provided that the above copyright notice appear in all copies and that
20 both that copyright notice and this permission notice appear in
21 supporting documentation, and that the name of the author not be
22 used in advertising or publicity pertaining to distribution of the
23 software without specific, written prior permission.
24
25 THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
26 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
27 AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
28 DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
29 AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
30 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
31 ***************************************/
32
33 /* Parts of this code stolen from mtest.c,
34 * part of the IMAP toolkit by Mark Crispin
35 */
36
37 /* Original version Copyright 1988 by The Leland Stanford Junior University
38 * Copyright 1999 by the University of Washington
39 *
40 * Permission to use, copy, modify, and distribute this software and its
41 * documentation for any purpose and without fee is hereby granted, provided
42 * that the above copyright notices appear in all copies and that both the
43 * above copyright notices and this permission notice appear in supporting
44 * documentation, and that the name of the University of Washington or The
45 * Leland Stanford Junior University not be used in advertising or publicity
46 * pertaining to distribution of the software without specific, written prior
47 * permission. This software is made available "as is", and
48 * THE UNIVERSITY OF WASHINGTON AND THE LELAND STANFORD JUNIOR UNIVERSITY
49 * DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE,
50 * INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
51 * FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE UNIVERSITY OF
52 * WASHINGTON OR THE LELAND STANFORD JUNIOR UNIVERSITY BE LIABLE FOR ANY
53 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
54 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
55 * CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF
56 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
57 *
58 */
59
60
61
62 /* Standard headers */
63 #include <stdio.h>
64 #include <signal.h>
65 #include <string.h>
66 #include <sys/time.h>
67 #include <sys/types.h>
68 #include <regex.h>
69
70
71
72 /* This is the local header */
73 #include "mm.h"
74
75
76 /* Comments about this module:
77
78 - Still need to free() the allocated chunks. This is not strictly necessary,
79 as this module will be called each time from anew and then will bail out,
80 so all the memory will be freed anyway.
81 But for the sake of cleanness, this needs to be done.
82 - A good idea would be to use glib for allocations, linked lists etc.
83 This still needs to be done.
84 - Comments to be added.
85 - Cleanup of internal functions.
86 - printfs should be replaced with calls to ER module
87
88 */
89
90
91
92 /***************************************
93 *
94 * API functions
95 *
96 ***************************************/
97
98 /* MM_decode. The main API function:
99 it parses the file mail_file, at the message mesgno,
100 and returns a structure pointing to files containing
101 all the different MIME parts, plus more information.
102 It also returns some headers of the message.
103 */
104
105 int MM_decode (
/* [<][>][^][v][top][bottom][index][help] */
106 char *mail_file, /* filename of the "mailbox" */
107 MM_header *mail_header, /* Headers: to be returned */
108 MM_xmp_list *part_list, /* List of MIME parts: to be returned */
109 long mesgno, /* Message number in the mailbox */
110 long debug /* debug level */
111 )
112 {
113
114 MAILSTREAM *stream = NULL; /* MAILSTREAM is defined in c-client */
115 char tmp[MAILTMPLEN]; /* MAILTMPLEN is set in c-client */
116 int mm_retcode; /* return code of the subroutine */
117
118
119 #include "linkage.c" /* c-client requires it to be included... */
120
121
122 sprintf (tmp, "%s", mail_file);
123
124 /* open mailbox and get the mail stream */
125 stream = mail_open (stream,tmp,debug ? OP_DEBUG : NIL);
126
127
128 /* Process the stream */
129 if (!stream)
130 {
131 printf ("Invalid mailbox: %s\n", mail_file);
132 return (1);
133 }
134 else
135 {
136
137 if (debug)
138 {
139 printf ("------------------ Message status:\n");
140 status (stream); /* report message status */
141 printf ("------------------ End of message status\n");
142 if (debug >= 2)
143 printf ("================== DEBUG: Calling mm function...\n");
144 }
145
146 /* run "user interface" */
147 mm_retcode = mm (stream,mail_header,part_list,mesgno,debug);
148
149 /* This doesn't work... It should free the memory allocated to the stream,
150 * but if you run the program in a loop, at the second time it coredumps.
151 * Seems like it wants to re-use the stream?
152 * This should be investigated.
153 */
154 /* mail_close(stream); */
155
156
157 return (mm_retcode);
158 }
159
160 /* We should never get here... */
161 /* return(1); */
162
163 } /* MM_decode() */
164
165
166 /*********************************************/
167
168
169 /* MM_store. Store stdin in a file. */
170
171 int MM_store (char *source_file, char *destination_file, long debug)
/* [<][>][^][v][top][bottom][index][help] */
172 {
173
174
175 #define LINESIZE STR_S
176 #define REGEXP "^From "
177 #define FIRSTCHARS 10
178
179 int c;
180 /* Input file pointer - Output file pointer */
181 FILE *ifp;
182 FILE *ofp;
183 FILE *actualfile; /* Actual "file" to be opened (can be stdin) */
184 time_t ti = time (0);
185 char line[LINESIZE];
186 char *tmpstr;
187 int linechars = 0;
188 int i;
189 short charcount = 0;
190 char firstline[LINESIZE];
191 short using_file = 0;
192
193
194 /* Check if we need to parse a file or stdin.
195 * We parse stdin if source_file is "-" .
196 */
197
198 if (strcmp(source_file,"-"))
199 {
200 if ((ifp = fopen(source_file,"r")) != NULL)
201 {
202 if (debug >= 3 ) printf ("Using file %s...\n",source_file);
203 actualfile = ifp;
204 using_file = 1;
205 }
206 else
207 {
208 printf ("ERROR: Could not open file %s for reading\n",source_file);
209 return(1);
210 }
211 }
212 else
213 {
214 if (debug >= 3 ) printf ("Using stdin...\n");
215 actualfile = stdin;
216 }
217
218 if ((ofp = fopen(destination_file,"w")) != NULL)
219 {
220 /* fprintf (ofp,"From dbase@whois.ripe.net %s",ctime (&ti)); */
221
222 /* This works. However, it can't be used since there is
223 no line length limitation in e-mail messages...
224 I leave it here if someone in the future has a better idea to do the trick.:) */
225 /* while (tmpstr = fgets(line, LINESIZE, stdin))
226 {
227 if (do_regex_test(REGEXP,tmpstr)) fprintf (ofp,">");
228 fputs (line,ofp);
229 } */
230
231 /* A non-trivial file dump from stdin.
232 The problem here is that we need to store
233 the beginning of each line to check if
234 the line starts with "From", in order to escape it with a ">".
235 The string-only method cannot be used, for mail messages don't have
236 a limit in line length
237 (we cannot use "gets" for buffer overflow risks).
238 Thus we need to use a "mixed" method,
239 grabbing the first "LINESIZE" characters in a string to check with
240 regexp. This string is then dumped. All the characters not
241 at the beginning of the string are directly dumped with putc. */
242
243 /* This is not a very generic algorithm...
244 It is only fit when you are looking
245 for a match at the beginning of a line.
246 BTW, the LINESIZE should be bigger
247 than the regexp you are trying to match...
248 And: it only starts to work at the second line of the text...
249 Basically, it's ugly but it fits our needs. */
250
251 /* Reset string */
252 for (i = 0; i < LINESIZE; i++)
253 firstline[i] = 0;
254
255
256 while ((c = getc(actualfile)) != EOF)
257 {
258 /* This is done to write the file so that it can be
259 interpreted by c-client as a mailbox in "unix" format:
260 the first line must start with "From " */
261
262 /* Get first characters to see if the first line is a "^From " line */
263 if (charcount < FIRSTCHARS)
264 {
265 firstline[charcount] = c;
266 charcount++;
267 continue;
268 }
269 if (charcount == FIRSTCHARS)
270 {
271 /* If the first line is not a "^From " line, put a fake one */
272 if (!do_regex_test(REGEXP,firstline))
273 fprintf (ofp,"From dbase@whois.ripe.net %s",ctime (&ti));
274 charcount++; /* otherwise it executes this block forever */
275 fprintf (ofp,"%s",firstline); /* dump all the string anyway */
276 }
277
278
279 /* Work with the rest of the message */
280 if ((c == 10) || /* new line or */
281 (linechars >= LINESIZE)) /* defined string length passed */
282 {
283 /* If there is a string in the buffer, the string is full or we have
284 a new line. We have to:
285 - check for the regexp
286 - dump the string in the file
287 - reset the string */
288 if (linechars)
289 {
290 tmpstr = line;
291 if (do_regex_test(REGEXP,tmpstr)) /* got regexp: */
292 fprintf (ofp,">"); /* Escape the line */
293 fprintf (ofp,"%s",line); /* dump string anyway */
294
295 /* Reset string */
296 linechars = 0;
297 for (i = 0; i < LINESIZE; i++)
298 line[i] = 0;
299 }
300
301 /* If we are at a new line, then start to get the string */
302 if (c == 10)
303 linechars = 1;
304 putc (c,ofp); /* Dump the character anyway */
305 }
306 else if (linechars) /* We are getting the string */
307 {
308 sprintf (line+linechars-1,"%c",c);
309 linechars++;
310 }
311 else /* Too far from the start of the line: */
312 putc (c,ofp); /* We just dump the character to the file */
313 }
314 fclose(ofp);
315 if (using_file) fclose(ifp);
316 return(0);
317 }
318 else
319 {
320 printf ("Error: couldn't open file %s for writing\n",destination_file);
321 return(1);
322 }
323 } /* MM_store() */
324
325
326 /*********************************************/
327
328 /* MM_cleanup. Cleans the files containing the MIME parts
329 when they're not needed anymore.
330 Todo: also clean memory. */
331
332 void MM_cleanup (MM_xmp_list *part_list, long debug)
/* [<][>][^][v][top][bottom][index][help] */
333 {
334 MM_xmp *p;
335 MM_xmp *q;
336
337 for (p = part_list->head; p != NULL; p = q)
338 {
339 q = p->next;
340 if (debug) printf ("Removing file %s...\n",p->file);
341 remove(p->file);
342 free(p->number);
343 free(p->type);
344 free(p->file);
345 free(p);
346 }
347
348 } /* MM_cleanup() */
349
350
351
352
353 /***************************************
354 *
355 * End of API functions
356 *
357 ***************************************/
358
359
360
361 /* User interface */
362
363 int mm (MAILSTREAM *stream, MM_header *hdr, MM_xmp_list *part_list, long mesgno, long debug)
/* [<][>][^][v][top][bottom][index][help] */
364 {
365
366 char *section;
367 char *result;
368 char tmp[MAILTMPLEN];
369 char strtmp[MAILTMPLEN];
370 char *mailtext;
371 unsigned long length;
372 long flags;
373 BODY *body;
374 STRINGLIST *lines;
375 STRINGLIST *cur;
376 char fileprefix[FILENAMELEN];
377 struct timeval *currenttime;
378 pid_t proc_id;
379 MM_b_section *secptr;
380 MM_bs_list *section_list;
381 MM_b_section *tmpsecptr;
382 char *tmpsection;
383 MM_xmp *newpart;
384 int retcode = 0;
385
386
387 /* Initialize the list of the body sections */
388
389 section_list = (MM_bs_list *)malloc(sizeof(MM_bs_list));
390 MM_bs_list_init (section_list);
391
392 /* Create the filename prefix for the output files */
393
394 currenttime = (struct timeval *)malloc(sizeof(struct timeval));
395 if (!gettimeofday(currenttime,NIL))
396 {
397 if (proc_id = getpid())
398 {
399 sprintf (fileprefix,"%s/%s.%ld-%d",TEMPDIR,GLOBALPREFIX,currenttime->tv_sec,(int)proc_id);
400 }
401 else printf ("ERROR: could not get Process ID\n");
402 }
403 else printf ("ERROR: Could not gettimeofday\n");
404 free(currenttime);
405
406
407 if (mesgno && (mesgno <= stream->nmsgs))
408 {
409
410 /* Get the headers we need. */
411
412 if (debug >= 2) printf ("================== DEBUG: my headers\n");
413
414
415 lines = mail_newstringlist ();
416 cur = lines;
417
418 /* Get information about the mentioned lines in the header */
419
420 hdr->from = get_header_line(stream,mesgno,cur,"From");
421
422 hdr->subject = get_header_line(stream,mesgno,cur,"Subject");
423
424 hdr->date = get_header_line(stream,mesgno,cur,"Date");
425
426 hdr->message_id = get_header_line(stream,mesgno,cur,"Message-ID");
427
428 hdr->reply_to = get_header_line(stream,mesgno,cur,"Reply-To");
429
430 hdr->cc = get_header_line(stream,mesgno,cur,"Cc");
431
432 mail_free_stringlist (&lines);
433
434 if (debug >= 2) printf ("================== DEBUG: After getting headers\n");
435
436
437
438 if (debug) printf ("Message number: %lu. Total messages: %lu\n", mesgno, stream->nmsgs);
439
440
441 /* Get structure of the message: body
442 (and envelope, which is unused) */
443
444 if (debug >= 2)
445 printf ("================== DEBUG: Calling mail_fetchstructure...\n");
446 mail_fetchstructure (stream,mesgno,&body);
447
448
449 if (debug >= 2)
450 printf ("================== DEBUG: Printing body information...\n");
451
452 if (body)
453 {
454 /*printf ("Body encoding: %d (%s)\n", body->encoding, body_encodings[body->encoding]);*/
455
456 /*
457 * Switch by supported body types.
458 * The supported body types are:
459 * - discrete:
460 * text/plain
461 * application/pgp
462 * application/pgp-signature (inside multipart/signed)
463 * - composite:
464 * multipart/mixed
465 * multipart/alternative
466 * multipart/signed
467 */
468 if (debug >= 2) printf ("================== DEBUG: Calling get_body_info...\n");
469 get_body_info (body,NIL,(long) 0, section_list, debug);
470 if (debug >= 2) printf ("================== DEBUG: After get_body_info...\n");
471
472 secptr = section_list->head;
473
474 if (debug >= 3)
475 {
476 printf ("================== DEBUG 3: number: %s\n",secptr->number);
477 printf ("================== DEBUG 3: type: %s\n",secptr->type);
478 }
479
480
481
482 switch (body->type)
483 {
484
485 case TYPETEXT:
486 mailtext = tmp;
487 if ((body->subtype) && (!strcmp(body->subtype,"PLAIN")))
488 {
489
490 /* Can this explode with huge messages? */
491 mailtext = mail_fetchtext(stream,mesgno);
492
493 if (debug >= 3)
494 {
495 printf ("Type text/plain\n");
496 printf ("Message contents:\n");
497 printf ("%s\n",mailtext);
498 }
499
500 secptr->supported = 1;
501
502 }
503 else
504 {
505 sprintf (mailtext,"Unsupported content type: %s",
506 body_types[body->type]);
507 if (body->subtype) sprintf (mailtext+strlen(mailtext),"/%s\n",body->subtype);
508 /* printf ("%s",mailtext); */
509 secptr->supported = 0;
510 }
511
512 /* Write in a file */
513
514 put_in_file (fileprefix,"1",mailtext,strlen(mailtext));
515
516 break;
517
518 case TYPEAPPLICATION:
519
520 mailtext = tmp;
521 if ((body->subtype) && (!strcmp(body->subtype,"PGP")))
522 {
523 mailtext = mail_fetchtext(stream,mesgno);
524
525 /* printf ("Type application/pgp\n");
526 printf ("Message contents:\n");
527 printf ("%s\n",mailtext); */
528
529 secptr->supported = 1;
530
531 }
532 else
533 {
534 sprintf (mailtext,"Unsupported content type: %s",
535 body_types[body->type]);
536 if (body->subtype) sprintf (mailtext+strlen(mailtext),"/%s\n",body->subtype);
537 /* printf ("%s",mailtext); */
538 secptr->supported = 0;
539 }
540
541 /* Write in a file */
542
543 put_in_file (fileprefix,"1",mailtext,strlen(mailtext));
544
545 break;
546
547 case TYPEMULTIPART:
548 if (body->subtype)
549 {
550 if ((!strcmp(body->subtype,"MIXED")) || (!strcmp(body->subtype,"ALTERNATIVE")) || (!strcmp(body->subtype,"SIGNED")))
551 {
552 /* printf ("Supported content type: %s/%s\n",body_types[body->type],body->subtype); */
553
554
555 flags = 0;
556 if (debug) printf ("Sections:\n");
557 while (secptr != NULL)
558 {
559 section = secptr->number;
560 if (debug)
561 {
562 printf("++++++++++++++++++++++++++++++++++++++++++++\n");
563 printf ("%s\n",section);
564 }
565 /*printf ("%s\n",secptr->type);*/
566
567 if ((!strcmp(secptr->type,"TEXT/PLAIN")) || (!strcmp(secptr->type,"APPLICATION/PGP-SIGNATURE")))
568 {
569 secptr->supported = 1;
570 result = mail_fetch_mime (stream, mesgno, section, &length, flags);
571
572
573 if (debug)
574 {
575 printf ("Supported content type: %s\n",secptr->type);
576 printf ("Length: %lu . Result: \n",length);
577 }
578
579 /* secptr->size: size of the contents of the body part.
580 length: size of the MIME header of the body part. */
581
582 secptr->mime_headers = (char *)malloc(length);
583
584 strncpy(secptr->mime_headers,result,(size_t)length);
585
586 /* printf ("--MIME headers:\n%s\n--End of MIME headers\n",secptr->mime_headers); */
587
588 secptr->contents = (char *)malloc(secptr->size);
589
590 strncpy(secptr->contents,result + length,(size_t)secptr->size);
591
592 /* Write in a file */
593
594 put_in_file (fileprefix,section,secptr->contents,secptr->size);
595
596 }
597 else
598 {
599 sprintf (strtmp,"Unsupported content type: %s\n",secptr->type);
600 secptr->supported = 0;
601 /* printf ("%s",strtmp); */
602 /* Write in a file */
603 put_in_file (fileprefix,section,strtmp,strlen(strtmp));
604 }
605
606
607 printf ("\n\n");
608
609
610
611 secptr = secptr->next;
612 }
613 }
614 else
615 {
616 sprintf (strtmp,"Unsupported content type: %s/%s\n",body_types[body->type],body->subtype);
617 secptr->supported = 0;
618 /* printf ("%s",strtmp); */
619 /* Write in a file */
620 put_in_file (fileprefix,"1",strtmp,strlen(strtmp));
621 /* Problem here - the notice is only written in the first file.
622 It is right, for we only should have one file for multipart/unsupported.
623 But from get_body_info, section_list is composed of all the parts
624 anyway...
625 a solution is to reduce here section_list to only one member,
626 as follows. */
627 secptr->next = NULL;
628 section_list->size = 1;
629
630 }
631 }
632 else
633 {
634
635 /* In current c-client implementation, we _should_ never get here,
636 since the subtype "unknown" is added if no subtype is
637 specified. */
638
639 sprintf (strtmp,"Unknown multipart subtype\n");
640 secptr->supported = 0;
641 /* printf ("%s",strtmp); */
642 /* Write in a file */
643 put_in_file (fileprefix,"1",strtmp,strlen(strtmp));
644 /* Same problem here as above: the notice is
645 only written in the first file. We reduce the list to
646 a single member. */
647 secptr->next = NULL;
648 section_list->size = 1;
649
650 }
651
652 break;
653
654 default:
655 sprintf (strtmp,"Unsupported content type: %s",body_types[body->type]);
656 secptr->supported = 0;
657 if (body->subtype) sprintf (strtmp+strlen(strtmp),"/%s\n",body->subtype);
658
659 /* printf ("%s",strtmp); */
660
661 /* Write in a file */
662 put_in_file (fileprefix,"1",strtmp,strlen(strtmp));
663 break;
664 }
665
666
667 /* Copy the relevant information to the structure used
668 by the API, MM_xmp */
669
670 tmpsecptr = section_list->head;
671
672 while (tmpsecptr != NULL)
673 {
674
675 newpart = (MM_xmp *)malloc(sizeof(MM_xmp));
676
677 tmpsection = tmpsecptr->number;
678
679 newpart->number = (char *)malloc(strlen(tmpsection) + 1);
680 sprintf (newpart->number,"%s",tmpsection);
681 newpart->file = (char *)malloc(strlen(fileprefix) + strlen(tmpsection) + 2);
682 sprintf (newpart->file,"%s-%s",fileprefix,tmpsection);
683 newpart->type = (char *)malloc(strlen(tmpsecptr->type));
684 sprintf (newpart->type,"%s",tmpsecptr->type);
685 /* printf ("%s\n",newpart->number);
686 printf ("%s\n",newpart->file);
687 if (debug) printf ("Reading file %s...\n",newpart->file);
688 read_file(newpart->file); */
689
690 newpart->supported = tmpsecptr->supported;
691 /* printf("Supported: %hd\n",newpart->supported); */
692
693 MM_xmp_list_ins_last(part_list, newpart);
694 tmpsecptr = tmpsecptr->next;
695 }
696
697 MM_bs_list_cleanup(section_list,debug);
698
699 }
700 else
701 {
702 puts ("No body information available");
703 retcode = 1;
704 }
705
706
707
708 }
709 else
710 {
711 printf ("Wrong message number: %lu. The maximum number of messages is %lu.\n",mesgno,stream->nmsgs);
712 retcode = 1;
713 }
714
715 return(retcode);
716
717 } /* mm() */
718
719
720 /* Internal functions */
721
722
723 /* MM get body information
724 * Accepts: BODY structure pointer
725 * prefix string
726 * index
727 * section list pointer
728 * debug switch
729 */
730
731 /* This function has been taken almost unchanged from mtest.c,
732 * in the IMAP distribution. There, it is called display_body.
733 */
734
735
736 void get_body_info (BODY *body,char *pfx,long i, MM_bs_list *section_list, long debug)
/* [<][>][^][v][top][bottom][index][help] */
737 {
738
739 char tmp[MAILTMPLEN];
740 char sectno[MAILTMPLEN];
741 char sectype[MAILTMPLEN];
742 char *s = tmp;
743 PARAMETER *par;
744 PART *part;
745 MM_b_section *newsection;
746
747
748 if (body->type == TYPEMULTIPART)
749 {
750 if (debug) printf ("++++multipart\n");
751 /* if not first time, extend prefix */
752 if (pfx) sprintf (tmp,"%s%ld.",pfx,++i);
753 else tmp[0] = '\0';
754 for (i = 0,part = body->nested.part; part; part = part->next)
755 get_body_info (&part->body,tmp,i++, section_list, debug);
756 }
757 else
758 { /* non-multipart, output oneline descriptor */
759 if (debug) printf ("++++nonmultipart\n");
760 if (!pfx) pfx = ""; /* dummy prefix if top level */
761
762 sprintf (s," %s%ld %s",pfx,++i,body_types[body->type]);
763
764 newsection = (MM_b_section *)malloc(sizeof(MM_b_section));
765
766 newsection->number = (char *)malloc(strlen(sectno)+1);
767 sprintf (sectno,"%s%ld",pfx,i);
768 sprintf (newsection->number,"%s",sectno);
769
770 sprintf (sectype, "%s",body_types[body->type]);
771
772 if (body->subtype)
773 {
774 sprintf (s += strlen (s),"/%s",body->subtype);
775 sprintf (sectype + strlen (sectype),"/%s",body->subtype);
776 }
777
778 newsection->type = (char *)malloc(strlen(sectype)+1);
779
780 sprintf (newsection->type,"%s",sectype);
781
782 /* Insert an element at the end of the list */
783
784 MM_bs_list_ins_last (section_list, newsection);
785
786
787
788 if (body->description) sprintf (s += strlen (s)," (%s)",body->description);
789
790
791 if ((par = body->parameter))
792 do
793 sprintf (s += strlen (s),";%s=%s",par->attribute,par->value);
794 while ((par = par->next));
795
796 if (body->id)
797 sprintf (s += strlen (s),", id = %s",body->id);
798
799 switch (body->type)
800 { /* bytes or lines depending upon body type */
801 case TYPEMESSAGE: /* encapsulated message */
802 case TYPETEXT: /* plain text */
803 sprintf (s += strlen (s)," (%lu lines)",body->size.lines);
804 newsection->size = body->size.bytes;
805 sprintf (s += strlen (s),"\n size: %lu",body->contents.text.size);
806 break;
807 default:
808 sprintf (s += strlen (s)," (%lu bytes)",body->size.bytes);
809 newsection->size = body->size.bytes;
810 break;
811 }
812 if (debug) puts (tmp); /* output this line */
813
814 }
815
816 return;
817
818 } /* get_body_info() */
819
820
821 /* MM status report
822 * Accepts: MAIL stream
823 */
824
825 void status (MAILSTREAM *stream)
/* [<][>][^][v][top][bottom][index][help] */
826 {
827 long i;
828 char date[MAILTMPLEN];
829 rfc822_date (date);
830 puts (date);
831 if (stream)
832 {
833 if (stream->mailbox)
834 printf (" %s mailbox: %s, %lu messages, %lu recent\n",
835 stream->dtb->name,stream->mailbox,stream->nmsgs,stream->recent);
836 else puts ("%No mailbox is open on this stream");
837 if (stream->user_flags[0])
838 {
839 printf ("Keywords: %s",stream->user_flags[0]);
840 for (i = 1; i < NUSERFLAGS && stream->user_flags[i]; ++i)
841 printf (", %s",stream->user_flags[i]);
842 puts ("");
843 }
844 }
845 } /* status() */
846
847
848
849 /*Initialize body_section list */
850
851 void MM_bs_list_init (MM_bs_list *section_list)
/* [<][>][^][v][top][bottom][index][help] */
852 {
853
854 section_list->size = 0;
855 section_list->head = NULL;
856 section_list->tail = NULL;
857 /* return; */
858
859 } /* MM_bs_list_init() */
860
861 /* Insert an element at the end of the body_section list */
862
863 void MM_bs_list_ins_last (MM_bs_list *section_list, MM_b_section *newsection)
/* [<][>][^][v][top][bottom][index][help] */
864 {
865
866 if (section_list->size == 0)
867 {
868 section_list->head = newsection;
869 section_list->tail = newsection;
870 section_list->size++;
871 }
872 else
873 {
874 section_list->tail->next = newsection;
875 section_list->tail = newsection;
876 section_list->size++;
877 }
878
879 newsection->next = NULL;
880
881 } /* MM_bs_list_ins_last() */
882
883
884 void MM_bs_list_cleanup (MM_bs_list *section_list, long debug)
/* [<][>][^][v][top][bottom][index][help] */
885 {
886 MM_b_section *p;
887 MM_b_section *q;
888
889 for (p = section_list->head; p != NULL; p = q)
890 {
891 q = p->next;
892 free(p->number);
893 free(p->type);
894 free(p->mime_headers);
895 free(p->contents);
896 free(p);
897 }
898
899
900 }
901
902
903 /*Initialize extracted_mimepart list */
904
905
906
907
908 void MM_xmp_list_init (MM_xmp_list *part_list)
/* [<][>][^][v][top][bottom][index][help] */
909 {
910
911 part_list->size = 0;
912 part_list->head = NULL;
913 part_list->tail = NULL;
914 /* return; */
915
916 } /* MM_xmp_list_init() */
917
918
919 /* Insert an element at the end of the body_section list */
920
921 void MM_xmp_list_ins_last (MM_xmp_list *part_list, MM_xmp *newpart)
/* [<][>][^][v][top][bottom][index][help] */
922 {
923
924 if (part_list->size == 0)
925 {
926 part_list->head = newpart;
927 part_list->tail = newpart;
928 part_list->size++;
929 }
930 else
931 {
932 part_list->tail->next = newpart;
933 part_list->tail = newpart;
934 part_list->size++;
935 }
936
937 newpart->next = NULL;
938
939 } /* MM_xmp_list_ins_last() */
940
941
942 char *get_header_line (MAILSTREAM *stream, long mesgno, STRINGLIST *cur, char *hdr_title)
/* [<][>][^][v][top][bottom][index][help] */
943 {
944
945 unsigned long offset;
946 size_t tmplength;
947 char *curtmp;
948 char *hdr_attr;
949 long a,b;
950
951
952 /* We need to insert the header title into a STRINGLIST structure, as
953 * this is the type that must be supplied to mail_fetchheader_full.
954 */
955
956 cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
957 cpystr (hdr_title)));
958
959 /* We don't want to return the header title, but only the contents.
960 * This offset allows us to strip the header title.
961 */
962
963 offset = cur->text.size + 2;
964
965 /* Get the header line, if it exists */
966
967 curtmp = mail_fetchheader_full (stream,mesgno,cur,NIL,NIL);
968
969 tmplength = strlen(curtmp);
970 hdr_attr = (char *)malloc(tmplength);
971
972 /* cur contains the header title string, like "From:", "Subject:" etc.
973 * tmplength is the length of the corresponding header line extracted
974 * from the message. If a real line is returned, the header title
975 * ("From:", "Subject:" etc.) will be contained within, hence
976 * tmplength >= cur->text.size . This means that if
977 * (cur->text.size > tmplength), no such header is present in the mail:
978 * we must return an (almost) empty string.
979 */
980
981 a = (long)tmplength;
982 b = (long)cur->text.size;
983 if (a > b)
984 {
985 sprintf (hdr_attr,"%s",curtmp + offset);
986 /* printf ("%s",hdr_attr); */
987 }
988 else
989 {
990 sprintf (hdr_attr,"\n\n");
991 }
992
993 return (hdr_attr);
994 } /* get_header_line() */
995
996
997 /* Subroutine for writing in a file */
998
999 void write_file (char *filename, char *text, size_t text_size)
/* [<][>][^][v][top][bottom][index][help] */
1000 {
1001
1002 FILE *fd;
1003 size_t i;
1004
1005 /* printf ("%s\n",filename); */
1006
1007 if ((fd = fopen(filename,"w")) != NULL)
1008 {
1009 for (i = 0; i < text_size; i++)
1010 fprintf (fd, "%c",text[i]);
1011 fclose(fd);
1012 }
1013 else
1014 printf ("Error: could not open file %s for writing\n",filename);
1015
1016 } /* write_file() */
1017
1018
1019 void read_file (char *filename)
/* [<][>][^][v][top][bottom][index][help] */
1020 {
1021
1022 FILE *fd;
1023 int c;
1024
1025 if ((fd = fopen (filename,"r")) != NULL)
1026 {
1027 while ((c = getc(fd)) != EOF)
1028 putc (c, stdout);
1029 fclose (fd);
1030 }
1031 else
1032 printf ("Error: could not open file %s for reading\n",filename);
1033
1034 } /* read_file() */
1035
1036
1037 void put_in_file (char *fileprefix, char *extension, char *text, size_t text_size)
/* [<][>][^][v][top][bottom][index][help] */
1038 {
1039
1040 char filename[FILENAMELEN];
1041
1042
1043 /* Write in a file */
1044
1045 sprintf (filename,"%s-%s",fileprefix,extension);
1046 /* printf ("%s\n",filename); */
1047
1048 write_file(filename,text,text_size);
1049
1050 }/* put_in_file() */
1051
1052
1053 /* Stolen from which_keytypes.c and converted to use regex.h instead of libgen.h */
1054
1055
1056 int do_regex_test (const char *pattern, char *string)
/* [<][>][^][v][top][bottom][index][help] */
1057 {
1058
1059 int match = 0;
1060
1061 /* These are not used, since REG_NOSUB is specified in regcomp() */
1062 size_t nmatch = 0;
1063 regmatch_t pmatch[1];
1064
1065 regex_t *re;
1066
1067 re = (regex_t *)malloc(STR_XL);
1068
1069 regcomp(re, pattern, REG_NOSUB);
1070 if (regexec(re, string, nmatch, pmatch, 0))
1071 match = 0;
1072 else
1073 match = 1;
1074
1075 regfree(re);
1076
1077 return(match);
1078
1079 } /* do_regex_test() */
1080
1081
1082 /* Interfaces to c-client.
1083 * They must be here for the code to be compiled,
1084 * but most can stay empty.
1085 */
1086
1087 void mm_searched (MAILSTREAM *stream,unsigned long number)
/* [<][>][^][v][top][bottom][index][help] */
1088 {
1089 }
1090
1091
1092 void mm_exists (MAILSTREAM *stream,unsigned long number)
/* [<][>][^][v][top][bottom][index][help] */
1093 {
1094 }
1095
1096
1097 void mm_expunged (MAILSTREAM *stream,unsigned long number)
/* [<][>][^][v][top][bottom][index][help] */
1098 {
1099 }
1100
1101
1102 void mm_flags (MAILSTREAM *stream,unsigned long number)
/* [<][>][^][v][top][bottom][index][help] */
1103 {
1104 }
1105
1106 void mm_notify (MAILSTREAM *stream,char *string,long errflg)
/* [<][>][^][v][top][bottom][index][help] */
1107 {
1108 }
1109
1110 void mm_list (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
/* [<][>][^][v][top][bottom][index][help] */
1111 {
1112 }
1113
1114 void mm_lsub (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
/* [<][>][^][v][top][bottom][index][help] */
1115 {
1116 }
1117
1118 void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
/* [<][>][^][v][top][bottom][index][help] */
1119 {
1120 }
1121
1122 void mm_log (char *string,long errflg)
/* [<][>][^][v][top][bottom][index][help] */
1123 {
1124 switch ((short) errflg) {
1125 case NIL:
1126 printf ("[%s]\n",string);
1127 break;
1128 case PARSE:
1129 case WARN:
1130 printf ("%%%s\n",string);
1131 break;
1132 case ERROR:
1133 printf ("?%s\n",string);
1134 break;
1135 }
1136 }
1137
1138 void mm_dlog (char *string)
/* [<][>][^][v][top][bottom][index][help] */
1139 {
1140 puts (string);
1141 }
1142
1143 void mm_login (NETMBX *mb,char *user,char *pwd,long trial)
/* [<][>][^][v][top][bottom][index][help] */
1144 {
1145 }
1146
1147 void mm_critical (MAILSTREAM *stream)
/* [<][>][^][v][top][bottom][index][help] */
1148 {
1149 }
1150
1151 void mm_nocritical (MAILSTREAM *stream)
/* [<][>][^][v][top][bottom][index][help] */
1152 {
1153 }
1154
1155 long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
/* [<][>][^][v][top][bottom][index][help] */
1156 {
1157 #if UNIXLIKE
1158 kill (getpid (),SIGSTOP);
1159 #else
1160 abort ();
1161 #endif
1162 return NIL;
1163 }
1164
1165 void mm_fatal (char *string)
/* [<][>][^][v][top][bottom][index][help] */
1166 {
1167 printf ("?%s\n",string);
1168 }
1169