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.17 $
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 /* hdr->content_type = get_header_line(stream,mesgno,cur,"Content-Type"); */
433 /* This gets all the line (with encoding etc.), while we only need the content-type itself */
434
435 hdr->content_type = (char *)malloc(STR_M);
436
437 mail_free_stringlist (&lines);
438
439 if (debug >= 2) printf ("================== DEBUG: After getting headers\n");
440
441
442
443 if (debug) printf ("Message number: %lu. Total messages: %lu\n", mesgno, stream->nmsgs);
444
445
446 /* Get structure of the message: body
447 (and envelope, which is unused) */
448
449 if (debug >= 2)
450 printf ("================== DEBUG: Calling mail_fetchstructure...\n");
451 mail_fetchstructure (stream,mesgno,&body);
452
453
454 if (debug >= 2)
455 printf ("================== DEBUG: Printing body information...\n");
456
457 if (body)
458 {
459 /*printf ("Body encoding: %d (%s)\n", body->encoding, body_encodings[body->encoding]);*/
460
461 /*
462 * Switch by supported body types.
463 * The supported body types are:
464 * - discrete:
465 * text/plain
466 * application/pgp
467 * application/pgp-signature (inside multipart/signed)
468 * - composite:
469 * multipart/mixed
470 * multipart/alternative
471 * multipart/signed
472 */
473 if (debug >= 2) printf ("================== DEBUG: Calling get_body_info...\n");
474 get_body_info (body,NIL,(long) 0, section_list, debug);
475 if (debug >= 2) printf ("================== DEBUG: After get_body_info...\n");
476
477 secptr = section_list->head;
478
479 if (debug >= 3)
480 {
481 printf ("================== DEBUG 3: number: %s\n",secptr->number);
482 printf ("================== DEBUG 3: type: %s\n",secptr->type);
483 }
484
485
486 sprintf (hdr->content_type,"%s",body_types[body->type]);
487 if (body->subtype)
488 { sprintf (hdr->content_type+strlen(hdr->content_type),"/%s\n\n",body->subtype); }
489
490 switch (body->type)
491 {
492
493 case TYPETEXT:
494 mailtext = tmp;
495 if ((body->subtype) && (!strcmp(body->subtype,"PLAIN")))
496 {
497
498 /* Can this explode with huge messages? */
499 mailtext = mail_fetchtext(stream,mesgno);
500
501 if (debug >= 3)
502 {
503 printf ("Type text/plain\n");
504 printf ("Message contents:\n");
505 printf ("%s\n",mailtext);
506 }
507
508 secptr->supported = 1;
509
510 }
511 else
512 {
513 sprintf (mailtext,"Unsupported content type: %s",
514 body_types[body->type]);
515 if (body->subtype) sprintf (mailtext+strlen(mailtext),"/%s\n",body->subtype);
516 /* printf ("%s",mailtext); */
517 secptr->supported = 0;
518 }
519
520 /* Write in a file */
521
522 put_in_file (fileprefix,"1",mailtext,strlen(mailtext));
523
524 break;
525
526 case TYPEAPPLICATION:
527
528 mailtext = tmp;
529 if ((body->subtype) && (!strcmp(body->subtype,"PGP")))
530 {
531 mailtext = mail_fetchtext(stream,mesgno);
532
533 /* printf ("Type application/pgp\n");
534 printf ("Message contents:\n");
535 printf ("%s\n",mailtext); */
536
537 secptr->supported = 1;
538
539 }
540 else
541 {
542 sprintf (mailtext,"Unsupported content type: %s",
543 body_types[body->type]);
544 if (body->subtype) sprintf (mailtext+strlen(mailtext),"/%s\n",body->subtype);
545 /* printf ("%s",mailtext); */
546 secptr->supported = 0;
547 }
548
549 /* Write in a file */
550
551 put_in_file (fileprefix,"1",mailtext,strlen(mailtext));
552
553 break;
554
555 case TYPEMULTIPART:
556 if (body->subtype)
557 {
558 if ((!strcmp(body->subtype,"MIXED")) || (!strcmp(body->subtype,"ALTERNATIVE")) || (!strcmp(body->subtype,"SIGNED")))
559 {
560 /* printf ("Supported content type: %s/%s\n",body_types[body->type],body->subtype); */
561
562
563 flags = 0;
564 if (debug) printf ("Sections:\n");
565 while (secptr != NULL)
566 {
567 section = secptr->number;
568 if (debug)
569 {
570 printf("++++++++++++++++++++++++++++++++++++++++++++\n");
571 printf ("%s\n",section);
572 }
573 /*printf ("%s\n",secptr->type);*/
574
575 if ((!strcmp(secptr->type,"TEXT/PLAIN")) || (!strcmp(secptr->type,"APPLICATION/PGP-SIGNATURE")))
576 {
577 secptr->supported = 1;
578 result = mail_fetch_mime (stream, mesgno, section, &length, flags);
579
580
581 if (debug)
582 {
583 printf ("Supported content type: %s\n",secptr->type);
584 printf ("Length: %lu . Result: \n",length);
585 }
586
587 /* secptr->size: size of the contents of the body part.
588 length: size of the MIME header of the body part. */
589
590 secptr->mime_headers = (char *)malloc(length);
591
592 strncpy(secptr->mime_headers,result,(size_t)length);
593
594 /* printf ("--MIME headers:\n%s\n--End of MIME headers\n",secptr->mime_headers); */
595
596 secptr->contents = (char *)malloc(secptr->size);
597
598 strncpy(secptr->contents,result + length,(size_t)secptr->size);
599
600 /* Write in a file */
601
602 put_in_file (fileprefix,section,secptr->contents,secptr->size);
603
604 }
605 else
606 {
607 sprintf (strtmp,"Unsupported content type: %s\n",secptr->type);
608 secptr->supported = 0;
609 /* printf ("%s",strtmp); */
610 /* Write in a file */
611 put_in_file (fileprefix,section,strtmp,strlen(strtmp));
612 }
613
614
615 printf ("\n\n");
616
617
618
619 secptr = secptr->next;
620 }
621 }
622 else
623 {
624 sprintf (strtmp,"Unsupported content type: %s/%s\n",body_types[body->type],body->subtype);
625 secptr->supported = 0;
626 /* printf ("%s",strtmp); */
627 /* Write in a file */
628 put_in_file (fileprefix,"1",strtmp,strlen(strtmp));
629 /* Problem here - the notice is only written in the first file.
630 It is right, for we only should have one file for multipart/unsupported.
631 But from get_body_info, section_list is composed of all the parts
632 anyway...
633 a solution is to reduce here section_list to only one member,
634 as follows. */
635 secptr->next = NULL;
636 section_list->size = 1;
637
638 }
639 }
640 else
641 {
642
643 /* In current c-client implementation, we _should_ never get here,
644 since the subtype "unknown" is added if no subtype is
645 specified. */
646
647 sprintf (strtmp,"Unknown multipart subtype\n");
648 secptr->supported = 0;
649 /* printf ("%s",strtmp); */
650 /* Write in a file */
651 put_in_file (fileprefix,"1",strtmp,strlen(strtmp));
652 /* Same problem here as above: the notice is
653 only written in the first file. We reduce the list to
654 a single member. */
655 secptr->next = NULL;
656 section_list->size = 1;
657
658 }
659
660 break;
661
662 default:
663 sprintf (strtmp,"Unsupported content type: %s",body_types[body->type]);
664 secptr->supported = 0;
665 if (body->subtype) sprintf (strtmp+strlen(strtmp),"/%s\n",body->subtype);
666
667 /* printf ("%s",strtmp); */
668
669 /* Write in a file */
670 put_in_file (fileprefix,"1",strtmp,strlen(strtmp));
671 break;
672 }
673
674
675 /* Copy the relevant information to the structure used
676 by the API, MM_xmp */
677
678 tmpsecptr = section_list->head;
679
680 while (tmpsecptr != NULL)
681 {
682
683 newpart = (MM_xmp *)malloc(sizeof(MM_xmp));
684
685 tmpsection = tmpsecptr->number;
686
687 newpart->number = (char *)malloc(strlen(tmpsection) + 1);
688 sprintf (newpart->number,"%s",tmpsection);
689 newpart->file = (char *)malloc(strlen(fileprefix) + strlen(tmpsection) + 2);
690 sprintf (newpart->file,"%s-%s",fileprefix,tmpsection);
691 newpart->type = (char *)malloc(2+strlen(tmpsecptr->type));
692 sprintf (newpart->type,"%s",tmpsecptr->type);
693 /* printf ("%s\n",newpart->number);
694 printf ("%s\n",newpart->file);
695 if (debug) printf ("Reading file %s...\n",newpart->file);
696 read_file(newpart->file); */
697
698 newpart->supported = tmpsecptr->supported;
699 /* printf("Supported: %hd\n",newpart->supported); */
700
701 MM_xmp_list_ins_last(part_list, newpart);
702 tmpsecptr = tmpsecptr->next;
703 }
704
705 MM_bs_list_cleanup(section_list,debug);
706
707 }
708 else
709 {
710 puts ("No body information available");
711 retcode = 1;
712 }
713
714
715
716 }
717 else
718 {
719 printf ("Wrong message number: %lu. The maximum number of messages is %lu.\n",mesgno,stream->nmsgs);
720 retcode = 1;
721 }
722
723 return(retcode);
724
725 } /* mm() */
726
727
728 /* Internal functions */
729
730
731 /* MM get body information
732 * Accepts: BODY structure pointer
733 * prefix string
734 * index
735 * section list pointer
736 * debug switch
737 */
738
739 /* This function has been taken almost unchanged from mtest.c,
740 * in the IMAP distribution. There, it is called display_body.
741 */
742
743
744 void get_body_info (BODY *body,char *pfx,long i, MM_bs_list *section_list, long debug)
/* [<][>][^][v][top][bottom][index][help] */
745 {
746
747 char tmp[MAILTMPLEN];
748 char sectno[MAILTMPLEN];
749 char sectype[MAILTMPLEN];
750 char *s = tmp;
751 PARAMETER *par;
752 PART *part;
753 MM_b_section *newsection;
754
755
756 if (body->type == TYPEMULTIPART)
757 {
758 if (debug) printf ("++++multipart\n");
759 /* if not first time, extend prefix */
760 if (pfx) sprintf (tmp,"%s%ld.",pfx,++i);
761 else tmp[0] = '\0';
762 for (i = 0,part = body->nested.part; part; part = part->next)
763 get_body_info (&part->body,tmp,i++, section_list, debug);
764 }
765 else
766 { /* non-multipart, output oneline descriptor */
767 if (debug) printf ("++++nonmultipart\n");
768 if (!pfx) pfx = ""; /* dummy prefix if top level */
769
770 sprintf (s," %s%ld %s",pfx,++i,body_types[body->type]);
771
772 newsection = (MM_b_section *)malloc(sizeof(MM_b_section));
773
774 sprintf (sectno,"%s%ld",pfx,i);
775 newsection->number = (char *)malloc(strlen(sectno)+1);
776 sprintf (newsection->number,"%s",sectno);
777
778 sprintf (sectype, "%s",body_types[body->type]);
779
780 if (body->subtype)
781 {
782 sprintf (s += strlen (s),"/%s",body->subtype);
783 sprintf (sectype + strlen (sectype),"/%s",body->subtype);
784 }
785
786 newsection->type = (char *)malloc(strlen(sectype)+1);
787
788 sprintf (newsection->type,"%s",sectype);
789
790 /* Insert an element at the end of the list */
791
792 MM_bs_list_ins_last (section_list, newsection);
793
794
795
796 if (body->description) sprintf (s += strlen (s)," (%s)",body->description);
797
798
799 if ((par = body->parameter))
800 do
801 sprintf (s += strlen (s),";%s=%s",par->attribute,par->value);
802 while ((par = par->next));
803
804 if (body->id)
805 sprintf (s += strlen (s),", id = %s",body->id);
806
807 switch (body->type)
808 { /* bytes or lines depending upon body type */
809 case TYPEMESSAGE: /* encapsulated message */
810 case TYPETEXT: /* plain text */
811 sprintf (s += strlen (s)," (%lu lines)",body->size.lines);
812 newsection->size = body->size.bytes;
813 sprintf (s += strlen (s),"\n size: %lu",body->contents.text.size);
814 break;
815 default:
816 sprintf (s += strlen (s)," (%lu bytes)",body->size.bytes);
817 newsection->size = body->size.bytes;
818 break;
819 }
820 if (debug) puts (tmp); /* output this line */
821
822 }
823
824 return;
825
826 } /* get_body_info() */
827
828
829 /* MM status report
830 * Accepts: MAIL stream
831 */
832
833 void status (MAILSTREAM *stream)
/* [<][>][^][v][top][bottom][index][help] */
834 {
835 long i;
836 char date[MAILTMPLEN];
837 rfc822_date (date);
838 puts (date);
839 if (stream)
840 {
841 if (stream->mailbox)
842 printf (" %s mailbox: %s, %lu messages, %lu recent\n",
843 stream->dtb->name,stream->mailbox,stream->nmsgs,stream->recent);
844 else puts ("%No mailbox is open on this stream");
845 if (stream->user_flags[0])
846 {
847 printf ("Keywords: %s",stream->user_flags[0]);
848 for (i = 1; i < NUSERFLAGS && stream->user_flags[i]; ++i)
849 printf (", %s",stream->user_flags[i]);
850 puts ("");
851 }
852 }
853 } /* status() */
854
855
856
857 /*Initialize body_section list */
858
859 void MM_bs_list_init (MM_bs_list *section_list)
/* [<][>][^][v][top][bottom][index][help] */
860 {
861
862 section_list->size = 0;
863 section_list->head = NULL;
864 section_list->tail = NULL;
865 /* return; */
866
867 } /* MM_bs_list_init() */
868
869 /* Insert an element at the end of the body_section list */
870
871 void MM_bs_list_ins_last (MM_bs_list *section_list, MM_b_section *newsection)
/* [<][>][^][v][top][bottom][index][help] */
872 {
873
874 if (section_list->size == 0)
875 {
876 section_list->head = newsection;
877 section_list->tail = newsection;
878 section_list->size++;
879 }
880 else
881 {
882 section_list->tail->next = newsection;
883 section_list->tail = newsection;
884 section_list->size++;
885 }
886
887 newsection->next = NULL;
888
889 } /* MM_bs_list_ins_last() */
890
891
892 void MM_bs_list_cleanup (MM_bs_list *section_list, long debug)
/* [<][>][^][v][top][bottom][index][help] */
893 {
894 MM_b_section *p;
895 MM_b_section *q;
896
897 for (p = section_list->head; p != NULL; p = q)
898 {
899 q = p->next;
900 free(p->number);
901 free(p->type);
902 /* free(p->mime_headers); */
903 /* free(p->contents); */
904 free(p);
905 }
906
907
908 }
909
910
911 /*Initialize extracted_mimepart list */
912
913
914
915
916 void MM_xmp_list_init (MM_xmp_list *part_list)
/* [<][>][^][v][top][bottom][index][help] */
917 {
918
919 part_list->size = 0;
920 part_list->head = NULL;
921 part_list->tail = NULL;
922 /* return; */
923
924 } /* MM_xmp_list_init() */
925
926
927 /* Insert an element at the end of the body_section list */
928
929 void MM_xmp_list_ins_last (MM_xmp_list *part_list, MM_xmp *newpart)
/* [<][>][^][v][top][bottom][index][help] */
930 {
931
932 if (part_list->size == 0)
933 {
934 part_list->head = newpart;
935 part_list->tail = newpart;
936 part_list->size++;
937 }
938 else
939 {
940 part_list->tail->next = newpart;
941 part_list->tail = newpart;
942 part_list->size++;
943 }
944
945 newpart->next = NULL;
946
947 } /* MM_xmp_list_ins_last() */
948
949
950 char *get_header_line (MAILSTREAM *stream, long mesgno, STRINGLIST *cur, char *hdr_title)
/* [<][>][^][v][top][bottom][index][help] */
951 {
952
953 unsigned long offset;
954 size_t tmplength;
955 char *curtmp;
956 char *hdr_attr;
957 long a,b;
958
959
960 /* We need to insert the header title into a STRINGLIST structure, as
961 * this is the type that must be supplied to mail_fetchheader_full.
962 */
963
964 cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
965 cpystr (hdr_title)));
966
967 /* We don't want to return the header title, but only the contents.
968 * This offset allows us to strip the header title.
969 */
970
971 offset = cur->text.size + 2;
972
973 /* Get the header line, if it exists */
974
975 curtmp = mail_fetchheader_full (stream,mesgno,cur,NIL,NIL);
976
977 tmplength = strlen(curtmp);
978 hdr_attr = (char *)malloc(tmplength + 2);
979
980 /* cur contains the header title string, like "From:", "Subject:" etc.
981 * tmplength is the length of the corresponding header line extracted
982 * from the message. If a real line is returned, the header title
983 * ("From:", "Subject:" etc.) will be contained within, hence
984 * tmplength >= cur->text.size . This means that if
985 * (cur->text.size > tmplength), no such header is present in the mail:
986 * we must return an (almost) empty string.
987 */
988
989 a = (long)tmplength;
990 b = (long)cur->text.size;
991 if (a > b)
992 {
993 sprintf (hdr_attr,"%s",curtmp + offset);
994 /* printf ("%s",hdr_attr); */
995 }
996 else
997 {
998 sprintf (hdr_attr,"\n\n");
999 }
1000
1001 return (hdr_attr);
1002 } /* get_header_line() */
1003
1004
1005 /* Subroutine for writing in a file */
1006
1007 void write_file (char *filename, char *text, size_t text_size)
/* [<][>][^][v][top][bottom][index][help] */
1008 {
1009
1010 FILE *fd;
1011 size_t i;
1012
1013 /* printf ("%s\n",filename); */
1014
1015 if ((fd = fopen(filename,"w")) != NULL)
1016 {
1017 for (i = 0; i < text_size; i++)
1018 fprintf (fd, "%c",text[i]);
1019 fclose(fd);
1020 }
1021 else
1022 printf ("Error: could not open file %s for writing\n",filename);
1023
1024 } /* write_file() */
1025
1026
1027 void read_file (char *filename)
/* [<][>][^][v][top][bottom][index][help] */
1028 {
1029
1030 FILE *fd;
1031 int c;
1032
1033 if ((fd = fopen (filename,"r")) != NULL)
1034 {
1035 while ((c = getc(fd)) != EOF)
1036 putc (c, stdout);
1037 fclose (fd);
1038 }
1039 else
1040 printf ("Error: could not open file %s for reading\n",filename);
1041
1042 } /* read_file() */
1043
1044
1045 void put_in_file (char *fileprefix, char *extension, char *text, size_t text_size)
/* [<][>][^][v][top][bottom][index][help] */
1046 {
1047
1048 char filename[FILENAMELEN];
1049
1050
1051 /* Write in a file */
1052
1053 sprintf (filename,"%s-%s",fileprefix,extension);
1054 /* printf ("%s\n",filename); */
1055
1056 write_file(filename,text,text_size);
1057
1058 }/* put_in_file() */
1059
1060
1061 /* Stolen from which_keytypes.c and converted to use regex.h instead of libgen.h */
1062
1063
1064 int do_regex_test (const char *pattern, char *string)
/* [<][>][^][v][top][bottom][index][help] */
1065 {
1066
1067 int match = 0;
1068
1069 /* These are not used, since REG_NOSUB is specified in regcomp() */
1070 size_t nmatch = 0;
1071 regmatch_t pmatch[1];
1072
1073 regex_t *re;
1074
1075 re = (regex_t *)malloc(STR_XL);
1076
1077 regcomp(re, pattern, REG_NOSUB);
1078 if (regexec(re, string, nmatch, pmatch, 0))
1079 match = 0;
1080 else
1081 match = 1;
1082
1083 regfree(re);
1084
1085 /* I thought regfree() would do this job...
1086 * Apparently, it doesn't.
1087 */
1088 free(re);
1089
1090 return(match);
1091
1092 } /* do_regex_test() */
1093
1094
1095 /* Interfaces to c-client.
1096 * They must be here for the code to be compiled,
1097 * but most can stay empty.
1098 */
1099
1100 void mm_searched (MAILSTREAM *stream,unsigned long number)
/* [<][>][^][v][top][bottom][index][help] */
1101 {
1102 }
1103
1104
1105 void mm_exists (MAILSTREAM *stream,unsigned long number)
/* [<][>][^][v][top][bottom][index][help] */
1106 {
1107 }
1108
1109
1110 void mm_expunged (MAILSTREAM *stream,unsigned long number)
/* [<][>][^][v][top][bottom][index][help] */
1111 {
1112 }
1113
1114
1115 void mm_flags (MAILSTREAM *stream,unsigned long number)
/* [<][>][^][v][top][bottom][index][help] */
1116 {
1117 }
1118
1119 void mm_notify (MAILSTREAM *stream,char *string,long errflg)
/* [<][>][^][v][top][bottom][index][help] */
1120 {
1121 }
1122
1123 void mm_list (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
/* [<][>][^][v][top][bottom][index][help] */
1124 {
1125 }
1126
1127 void mm_lsub (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
/* [<][>][^][v][top][bottom][index][help] */
1128 {
1129 }
1130
1131 void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
/* [<][>][^][v][top][bottom][index][help] */
1132 {
1133 }
1134
1135 void mm_log (char *string,long errflg)
/* [<][>][^][v][top][bottom][index][help] */
1136 {
1137 switch ((short) errflg) {
1138 case NIL:
1139 printf ("[%s]\n",string);
1140 break;
1141 case PARSE:
1142 case WARN:
1143 printf ("%%%s\n",string);
1144 break;
1145 case ERROR:
1146 printf ("?%s\n",string);
1147 break;
1148 }
1149 }
1150
1151 void mm_dlog (char *string)
/* [<][>][^][v][top][bottom][index][help] */
1152 {
1153 puts (string);
1154 }
1155
1156 void mm_login (NETMBX *mb,char *user,char *pwd,long trial)
/* [<][>][^][v][top][bottom][index][help] */
1157 {
1158 }
1159
1160 void mm_critical (MAILSTREAM *stream)
/* [<][>][^][v][top][bottom][index][help] */
1161 {
1162 }
1163
1164 void mm_nocritical (MAILSTREAM *stream)
/* [<][>][^][v][top][bottom][index][help] */
1165 {
1166 }
1167
1168 long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
/* [<][>][^][v][top][bottom][index][help] */
1169 {
1170 #if UNIXLIKE
1171 kill (getpid (),SIGSTOP);
1172 #else
1173 abort ();
1174 #endif
1175 return NIL;
1176 }
1177
1178 void mm_fatal (char *string)
/* [<][>][^][v][top][bottom][index][help] */
1179 {
1180 printf ("?%s\n",string);
1181 }
1182