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