## 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_xmp_list_init
10. MM_xmp_list_ins_last
11. get_header_line
12. write_file
13. read_file
14. put_in_file
15. perform_regex_test
16. mm_searched
17. mm_exists
18. mm_expunged
19. mm_flags
20. mm_notify
21. mm_list
22. mm_lsub
23. mm_status
24. mm_log
25. mm_dlog
26. mm_login
27. mm_critical
28. mm_nocritical
29. mm_diskerror
30. 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

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