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 (
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
1022 | {
1023 | }
1024 |
1025 |
1026 | void mm_exists (MAILSTREAM *stream,unsigned long number)
1027 | {
1028 | }
1029 |
1030 |
1031 | void mm_expunged (MAILSTREAM *stream,unsigned long number)
1032 | {
1033 | }
1034 |
1035 |
1036 | void mm_flags (MAILSTREAM *stream,unsigned long number)
1037 | {
1038 | }
1039 |
1040 | void mm_notify (MAILSTREAM *stream,char *string,long errflg)
1041 | {
1042 | }
1043 |
1044 | void mm_list (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
1045 | {
1046 | }
1047 |
1048 | void mm_lsub (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
1049 | {
1050 | }
1051 |
1052 | void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
1053 | {
1054 | }
1055 |
1056 | void mm_log (char *string,long errflg)
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)
1073 | {
1074 | puts (string);
1075 | }
1076 |
1077 | void mm_login (NETMBX *mb,char *user,char *pwd,long trial)
1078 | {
1079 | }
1080 |
1081 | void mm_critical (MAILSTREAM *stream)
1082 | {
1083 | }
1084 |
1085 | void mm_nocritical (MAILSTREAM *stream)
1086 | {
1087 | }
1088 |
1089 | long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
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)
1100 | {
1101 | printf ("?%s\n",string);
1102 | }
1103 |