## modules/mm/mm.c

/* [<][>][^][v][top][bottom][index][help] */

## FUNCTIONS

This source file includes following functions.

1. MM_decode
2. MM_store
3. MM_cleanup
4. mm
5. get_body_info
6. status
7. MM_bs_list_init
8. MM_bs_list_ins_last
9. MM_bs_list_cleanup
10. MM_xmp_list_init
11. MM_xmp_list_ins_last
12. get_header_line
13. write_file
14. read_file
15. put_in_file
16. do_regex_test
17. mm_searched
18. mm_exists
19. mm_expunged
20. mm_flags
21. mm_notify
22. mm_list
23. mm_lsub
24. mm_status
25. mm_log
26. mm_dlog
27. mm_login
28. mm_critical
29. mm_nocritical
30. mm_diskerror
31. mm_fatal

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

/* [<][>][^][v][top][bottom][index][help] */