Source File modules/mm/mm.c

    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 |