## modules/mm/mm.c

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

## FUNCTIONS

This source file includes following functions.

1. MM_store
2. MM_get_msg_headers
3. MM_extract_mime
4. is_supported_MIMEtype
5. dispatch_to_driver
6. parse_text_plain
7. parse_message_rfc822
8. parse_multipart_alternative
9. parse_multipart_signed
10. status
11. get_mail_hdr_field
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: 2.24 $
       3
       4   mm - MIME Parser module. Functions to parse a mail message part,
       5   find if it is MIME-encapsulated, dispatch the part to the
       6   appropriate drivers (also included) and return tree nodes
       7   with all MIME information.
       8
       9   Status: COMPLETE, NOT REVUED, TESTED
      10
      11   Design and implementation by: daniele@ripe.net
      12
      13   ******************/ /******************
      14   Copyright (c) 2000                              RIPE NCC
      15
      16   All Rights Reserved
      17
      18   Permission to use, copy, modify, and distribute this software and its
      19   documentation for any purpose and without fee is hereby granted,
      20   provided that the above copyright notice appear in all copies and that
      21   both that copyright notice and this permission notice appear in
      22   supporting documentation, and that the name of the author not be
      23   used in advertising or publicity pertaining to distribution of the
      24   software without specific, written prior permission.
      25
      26   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
      27   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
      28   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
      29   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
      30   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      31   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      32   ***************************************/
      33
      34 /* Pieces of this code stolen and/or adapted from mtest.c,
      35  * part of the IMAP toolkit by Mark Crispin:
      36  */
      37
      38 /* Original version Copyright 1988 by The Leland Stanford Junior University
      39  * Copyright 1999 by the University of Washington
      40  *
      41  *  Permission to use, copy, modify, and distribute this software and its
      42  * documentation for any purpose and without fee is hereby granted, provided
      43  * that the above copyright notices appear in all copies and that both the
      44  * above copyright notices and this permission notice appear in supporting
      45  * documentation, and that the name of the University of Washington or The
      46  * Leland Stanford Junior University not be used in advertising or publicity
      47  * pertaining to distribution of the software without specific, written prior
      48  * permission.  This software is made available "as is", and
      49  * THE UNIVERSITY OF WASHINGTON AND THE LELAND STANFORD JUNIOR UNIVERSITY
      50  * DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE,
      51  * INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
      52  * FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE UNIVERSITY OF
      53  * WASHINGTON OR THE LELAND STANFORD JUNIOR UNIVERSITY BE LIABLE FOR ANY
      54  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
      55  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
      56  * CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF
      57  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      58  *
      59  */
      60
      61
      62
      63 /**************************
      64
      65
      66 "Every program attempts to expand until it can read mail.
      67  Those programs which cannot so expand are replaced by
      68  ones which can."
      69                 (Jamie Zawinski)
      70
      71
      72 **************************/
      73
      74
      75
      76 /* Standard headers */
      77 #include <stdio.h>
      78 #include <signal.h>
      79 #include <string.h>
      80 #include <sys/time.h>
      81 #include <sys/types.h>
      82 /* #include <sys/param.h> */
      83 #include <netdb.h>
      84 #include <regex.h>
      85 #include <unistd.h>
      86
      87
      88
      89 /* This is the local header */
      90 #include "mm.h"
      91
      92 /* Other RIP headers */
      93 #include "erroutines.h"
      94
      95
      96 /*
      97  * Globals to store shared data for tree nodes
      98  * These variables come from EP
      99  */
     100
     101 extern char EP_outputPrefix[FILENAME_LENGTH];
     102 extern char EP_keyRing[FILENAME_LENGTH];
     103 extern int EP_TreeHeight;
     104 extern int  EP_Node_ID;
     105
     106 /* Global variables to be used in this module */
     107 long debug = DEFAULT_DEBUG;
     108
     109 char *supported_MIME_types[MAXSUPPTYPES] = {
     110   "UNKNOWN/UNKNOWN", "TEXT/PLAIN", "APPLICATION/PGP", "MULTIPART/SIGNED",
     111   "MULTIPART/MIXED", "MULTIPART/ALTERNATIVE", "MULTIPART/DIGEST",
     112   "MESSAGE/RFC822"
     113 };
     114
     115 long pass = 0;
     116
     117
     118 /*
     119    FIXMEs:
     120    - Revise the whole debug system, debug messages etc. - right now
     121      an enormous and globally useless quantity of information is dumped.
     122 */
     123
     124
     125 /*+++++++++++++++++++++++++++++++++++++++
     126
     127   API functions
     128
     129   +++++++++++++++++++++++++++++++++++++++*/
     130
     131
     132
     133 /*++++++++++
     134  *
     135  * MM_store(). Stores a file (or stdin) in another file,
     136  * "escaping" the lines starting with "From " by adding
     137  * a ">" sign. This is necessary because we need to deal
     138  * with files that are "unix mailboxes".
     139  *
     140  * This function puts a limit to the line size that a mail
     141  * message may have; officially, there is no limit to this size,
     142  * but we prefer to add this limit to avoid buffer overflow.
     143  * The line size limit is MAXBUFSIZE, defined in mm.h .
     144  *
     145  ++++++++++*/
     146
     147
     148 int MM_store (char *source_file, char *destination_file, long custom_debug)
         /* [<][>][^][v][top][bottom][index][help] */
     149 {
     150
     151
     152 /* The regexp we will be looking for */
     153 #define REGEXP "^From "
     154
     155
     156   char line[MAXBUFSIZE];
     157   FILE *ifp;
     158   FILE *ofp;
     159   FILE *actualfile; /* Actual "file" to be opened (can be stdin) */
     160   char *tmpstr;
     161   short using_file = 0;
     162   long numlines = 0;
     163   time_t ti = time (0);
     164
     165
     166
     167   if (custom_debug)
     168     debug = custom_debug;
     169
     170   /* Check if we need to parse a file or stdin.
     171    * We parse stdin if source_file is "-" .
     172    */
     173
     174   if (strcmp(source_file,"-"))
     175     {
     176       if ((ifp = fopen(source_file,"r")) != NULL)
     177         {
     178           ER_dbg_va (FAC_MM, ASP_MM_GEN, "MM_store: input file %s",source_file);
     179           actualfile = ifp;
     180           using_file = 1;
     181         }
     182       else
     183         {
     184           /* XXX Use perror to state reason? */
     185           ER_perror(FAC_MM, MM_CANTOPEN, "%s for reading", source_file);
     186           die;
     187         }
     188     }
     189   else
     190     {
     191       ER_dbg_va (FAC_MM, ASP_MM_GEN, "MM_store: input from stdin");
     192       actualfile = stdin;
     193     }
     194
     195   if ((ofp = fopen(destination_file,"w")) != NULL)
     196     {
     197       while ((tmpstr = fgets(line, MAXBUFSIZE, actualfile)) != NULL)
     198         {
     199           numlines++;
     200           if (strlen(line) >= MAXBUFSIZE - 1)
     201             {
     202               ER_inf_va(FAC_MM, ASP_MM_SEC, "Line too long error. Possible buffer overflow attempt.");
     203               ER_perror(FAC_MM, MM_LINETOOLONG, "%ld",numlines);
     204               /* XXX Should be handled better - report line too long to caller,
     205                  so that a failed ack can be sent */
     206               die;
     207             }
     208           if (numlines == 1)
     209             {
     210               /* If the first line is not a "^From " line, put a fake one */
     211               if (!do_regex_test(REGEXP,(char *)line))
     212                   fprintf (ofp,"From dbase@whois.ripe.net %s",ctime (&ti));
     213               fputs (line,ofp);
     214             }
     215           else
     216             {
     217               if (do_regex_test(REGEXP,(char *)line)) fprintf (ofp,">");
     218               fputs (line,ofp);
     219             }
     220         }
     221       fclose(ofp);
     222       if (using_file) fclose(ifp);
     223       return(0);
     224     }
     225   else
     226     {
     227       /* XXX Use perror to state reason? */
     228       ER_perror(FAC_MM, MM_CANTOPEN, "%s for writing", destination_file);
     229       die;
     230     }
     231
     232   /* Even though we should never get here... */
     233   return(0);
     234
     235 } /* MM_store() */
     236
     237
     238
     239 /**********
     240  *
     241  * MM_get_msg_headers(). Get the headers of a mail contained in a file.
     242  *
     243  **********/
     244
     245 int MM_get_msg_headers(
         /* [<][>][^][v][top][bottom][index][help] */
     246                    const char *mail_file,                       /* Input mail file */
     247                    EP_Mail_Descr *mail_descr,           /* Structure containing the headers */
     248                    long mesgno,                         /* msg number in the input file */
     249                    long custom_debug                    /* debug level */
     250                    )
     251 {
     252   MAILSTREAM *stream = NULL;            /* MAILSTREAM is defined in c-client */
     253   char tmp[MAILTMPLEN];                 /* MAILTMPLEN is set in c-client */
     254   int retcode;                          /* return code of the subroutine */
     255   STRINGLIST *lines;                    /* STRINGLIST is defined in c-client */
     256   STRINGLIST *cur;
     257   BODY *body;
     258
     259 #include "linkage.c"            /* c-client requires it to be included... */
     260
     261
     262   /* If the supplied debug level is not null, then the global debug level
     263    * takes that value
     264    */
     265   if (custom_debug)
     266     debug = custom_debug;
     267
     268
     269   /* open mailbox and get the mail stream */
     270   sprintf (tmp, "%s", mail_file);
     271   stream = mail_open (stream,tmp,debug ? OP_DEBUG : NIL);
     272
     273   /* Process the stream */
     274   if (!stream)
     275     {
     276       ER_perror(FAC_MM, MM_INVMBX, "%s", mail_file);
     277       die;
     278     }
     279   else
     280     {
     281       ER_inf_va (FAC_MM, ASP_MM_GEN, "Getting message headers.");
     282       ER_dbg_va (FAC_MM, ASP_MM_GEN, "Message status:");
     283       status (stream);                  /* report message status */
     284       ER_dbg_va (FAC_MM, ASP_MM_GEN, "End of message status.");
     285
     286       /* Get the headers */
     287
     288       lines = mail_newstringlist ();
     289       cur = lines;
     290
     291       /* Get information about the mentioned lines in the header */
     292
     293
     294       mail_descr->from = get_mail_hdr_field(stream, mesgno, cur, "From");
     295
     296       mail_descr->subject = get_mail_hdr_field(stream, mesgno, cur, "Subject");
     297
     298       mail_descr->date = get_mail_hdr_field(stream, mesgno, cur, "Date");
     299
     300       mail_descr->message_id = get_mail_hdr_field(stream, mesgno, cur, "Message-Id");
     301
     302       mail_descr->reply_to = get_mail_hdr_field(stream, mesgno, cur, "Reply-To");
     303
     304       mail_descr->cc = get_mail_hdr_field(stream, mesgno, cur, "Cc");
     305
     306
     307
     308       mail_descr->content_type = (Mail_Header_Field *)malloc(sizeof(Mail_Header_Field));
     309       /* This gets all the line (with encoding etc.) */
     310       /* mail_descr->content_type = get_mail_hdr_field(stream,mesgno,cur,"Content-Type"); */
     311
     312       /* This only gets the content-type itself in canonized form: */
     313       mail_fetchstructure(stream,mesgno,&body);
     314       if (body)
     315         {
     316           mail_descr->content_type->field = (char *)malloc(STR_M);
     317           mail_descr->content_type->next = NULL;
     318           sprintf(mail_descr->content_type->field,"%s",body_types[body->type]);
     319           if (body->subtype)
     320             sprintf(mail_descr->content_type->field+strlen(mail_descr->content_type->field),"/%s",body->subtype);
     321           sprintf(mail_descr->content_type->field+strlen(mail_descr->content_type->field),"\n\n");
     322         }
     323
     324       mail_free_stringlist (&lines);
     325
     326       ER_inf_va (FAC_MM, ASP_MM_GEN, "Got message headers.");
     327
     328
     329
     330       mail_close(stream);
     331
     332       retcode = 0;
     333
     334
     335     }
     336
     337
     338   return(retcode);
     339
     340 } /* MM_get_msg_headers() */
     341
     342
     343
     344 /*
     345  * MM_extract_mime(): extract MIME information
     346  * This function was inspired by display_body() in mtest.c,
     347  * in the IMAP distribution. It has been largely re-engineered
     348  * to support MIME, and be modular.
     349  * It now only acts as an initializer of the mail stream,
     350  * sending then the stream to be dispatched to the appropriate
     351  * MIME drivers.
     352  */
     353
     354
     355
     356
     357 int MM_extract_mime (
         /* [<][>][^][v][top][bottom][index][help] */
     358                      const char *sourcefile,                    /* Input file containing the mail */
     359                      char *pfx,                         /* "prefix": this can be NULL at the
     360                                                          * first call of the function */
     361                      EP_mail_node *mailnode,            /* initialized node where to stock info */
     362                      long custom_debug                  /* debug level */
     363                      )
     364 {
     365
     366   MAILSTREAM *stream = NULL;            /* MAILSTREAM is defined in c-client */
     367   BODY *body;                           /* BODY is defined in c-client */
     368   char tmp[MAILTMPLEN];                 /* MAILTMPLEN is set in c-client */
     369   int retcode = 0;                      /* return code of the subroutine */
     370   long mesgno = 1;
     371
     372
     373 #include "linkage.c"            /* c-client requires it to be included... */
     374
     375   /*
     376    * This (global) variable counts the number of times we pass through
     377    * MM_extract_mime().
     378    * It is useful in generating unique temporary files (see below).
     379    */
     380
     381   pass++;
     382   ER_inf_va (FAC_MM, ASP_MM_GEN, "MM_extract_mime, pass %ld",pass);
     383
     384   if (custom_debug)
     385     debug = custom_debug;
     386
     387   /* ER_dbg_va (FAC_MM, ASP_MM_GEN, " EP_outputPrefix: %s",EP_outputPrefix);
     388      ER_dbg_va (FAC_MM, ASP_MM_GEN, " EP_keyRing: %s",EP_keyRing); */
     389
     390
     391   /* open file and get the mail stream from there*/
     392
     393   sprintf (tmp, "%s", sourcefile);
     394
     395   stream = mail_open (stream,tmp,debug ? OP_DEBUG : NIL);
     396
     397   /* Process the stream */
     398   if (!stream)
     399     {
     400       ER_perror(FAC_MM, MM_INVMBX, "%s", sourcefile);
     401       die;
     402     }
     403   else
     404     {
     405       if (debug >=2)
     406         {
     407           ER_inf_va (FAC_MM, ASP_MM_GEN, "Getting message headers.");
     408           ER_dbg_va (FAC_MM, ASP_MM_GEN, "Message status:");
     409           status (stream);                      /* report message status */
     410           ER_dbg_va (FAC_MM, ASP_MM_GEN, "End of message status.");
     411         }
     412       if (debug >= 2)
     413         ER_dbg_va (FAC_MM, ASP_MM_GEN, "Calling mail_fetchstructure...");
     414       mail_fetchstructure (stream,mesgno,&body);
     415
     416       if (body)
     417         {
     418           ER_dbg_va (FAC_MM, ASP_MM_GEN, "Got body, dispatching to drivers...");
     419           dispatch_to_driver(stream, body, pfx, mailnode);
     420         }
     421
     422     }
     423
     424   ER_dbg_va (FAC_MM, ASP_MM_GEN, "Closing the stream %s...",stream->mailbox);
     425   mail_close(stream);
     426   ER_dbg_va (FAC_MM, ASP_MM_GEN, "Stream Closed.");
     427
     428
     429   return(retcode);
     430
     431 } /* MM_extract_mime() */
     432
     433
     434
     435 /*********************************************/
     436
     437 /***************************************
     438  *
     439  * End of API functions
     440  *
     441  ***************************************/
     442
     443
     444
     445 /* Internal functions */
     446
     447 t_MM_type is_supported_MIMEtype (BODY *body)
         /* [<][>][^][v][top][bottom][index][help] */
     448 {
     449
     450   char *mimetype_string;
     451   char tmpstr[STR_S];
     452   char *tmptype = tmpstr;
     453   int i;
     454   t_MM_type mtypecode = 0;
     455
     456
     457   /* mimetype_string is the MIME type of the message */
     458   mimetype_string = (char *)malloc(STR_S);
     459   sprintf (mimetype_string,"%s",body_types[body->type]);
     460   if (body->subtype)
     461     sprintf (mimetype_string + strlen(mimetype_string),"/%s",body->subtype);
     462
     463   /*
     464    * We cycle to compare the MIME type of the message
     465    * to each of the MIME types we support
     466    */
     467   i = 0;
     468   tmptype = supported_MIME_types[i];
     469
     470   while ((i < MAXSUPPTYPES) && (tmptype))
     471     {
     472       if (!strcmp(tmptype,mimetype_string))
     473         {
     474           mtypecode = i;
     475           break;
     476         }
     477       tmptype = supported_MIME_types[++i];
     478     }
     479
     480   free(mimetype_string);
     481
     482   return(mtypecode);
     483
     484 } /* is_supported_MIMEtype() */
     485
     486
     487
     488 /****
     489  *
     490  * dispatch_to_driver()
     491  * This function dispatches a message to the proper driver
     492  * which will parse it, following the MIME type
     493  *
     494  ****/
     495
     496 void dispatch_to_driver(MAILSTREAM *stream, BODY *body, char *pfx, EP_mail_node *mailnode)
         /* [<][>][^][v][top][bottom][index][help] */
     497 {
     498
     499   t_MM_type is_supported;
     500
     501   is_supported = is_supported_MIMEtype(body);
     502   /* We assign the given MIME Type to the node */
     503   mailnode->MIMEContentType = is_supported;
     504
     505
     506   ER_dbg_va (FAC_MM, ASP_MM_GEN, " mailnode->MIMEContentType: %s",supported_MIME_types[mailnode->MIMEContentType]);
     507
     508   if (!strcmp(supported_MIME_types[is_supported],"TEXT/PLAIN"))
     509     {
     510       parse_text_plain(stream, body, pfx, mailnode);
     511     }
     512   else if (!strcmp(supported_MIME_types[is_supported],"APPLICATION/PGP"))
     513     {
     514       parse_application_pgp(stream, body, pfx, mailnode);
     515     }
     516   else if (!strcmp(supported_MIME_types[is_supported],"MULTIPART/ALTERNATIVE"))
     517     {
     518       parse_multipart_alternative(stream, body, pfx, mailnode);
     519     }
     520   else if (!strcmp(supported_MIME_types[is_supported],"MULTIPART/MIXED"))
     521     {
     522       parse_multipart_mixed(stream, body, pfx, mailnode);
     523     }
     524   else if (!strcmp(supported_MIME_types[is_supported],"MULTIPART/SIGNED"))
     525     {
     526       parse_multipart_signed(stream, body, pfx, mailnode);
     527     }
     528   else if (!strcmp(supported_MIME_types[is_supported],"MULTIPART/DIGEST"))
     529     {
     530       parse_multipart_digest(stream, body, pfx, mailnode);
     531     }
     532   else if (!strcmp(supported_MIME_types[is_supported],"MESSAGE/RFC822"))
     533     {
     534       parse_message_rfc822(stream, body, pfx, mailnode);
     535     }
     536   else
     537     {
     538       /* It's not a supported MIMEtype... */
     539       parse_unknown_unknown(stream, body, pfx, mailnode);
     540     }
     541
     542 } /* dispatch_to_driver() */
     543
     544
     545 void parse_text_plain(MAILSTREAM *stream, BODY *body, char *pfx, EP_mail_node *mailnode)
         /* [<][>][^][v][top][bottom][index][help] */
     546 {
     547
     548   char tmp[MAILTMPLEN];
     549   char *mailtext;
     550
     551
     552   if (debug >= 2)
     553     ER_dbg_va (FAC_MM, ASP_MM_GEN, " Lines: %lu",body->size.lines);
     554
     555   if (pfx == NULL)                      /* If top level, is not inside a multipart */
     556     {
     557       if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "MAILNODE->FILE: %s",mailnode->file);
     558       /* The filename of the root node has to be redefined to the processed file */
     559       /* remove(mailnode->file); */ /* This causes complaints by mail_close() */
     560       free(mailnode->file);
     561       mailnode->file = (char *)malloc(FILENAME_LENGTH);
     562       sprintf(mailnode->file,"%s%d",EP_outputPrefix,mailnode->nodeID);
     563       if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "MAILNODE->FILE: %s",mailnode->file);
     564     }
     565   else
     566
     567   ER_dbg_va (FAC_MM, ASP_MM_GEN, " mailnode->file: %s",mailnode->file);
     568
     569   /* Get the plain text contents of the message */
     570   mailtext = tmp;
     571   mailtext = mail_fetchtext(stream, 1);
     572
     573   if (debug >= 2)
     574     {
     575       ER_dbg_va (FAC_MM, ASP_MM_GEN, "Message contents:");
     576       ER_dbg_va (FAC_MM, ASP_MM_GEN, "\n\n%s\n",mailtext);
     577     }
     578
     579
     580   /* Place the results in the file pointed by the node*/
     581   write_file(mailnode->file,mailtext,strlen(mailtext));
     582
     583   PA_ParseMessage(mailnode);
     584
     585   /* if (debug) printf ("mailnode->nodeID: %d\n",mailnode->nodeID); */
     586   /* if (debug) printf ("mailnode->MIMEContentType: %d\n",mailnode->MIMEContentType); */
     587
     588 }
     589
     590 void parse_message_rfc822(MAILSTREAM *stream, BODY *body, char *pfx, EP_mail_node *mailnode)
         /* [<][>][^][v][top][bottom][index][help] */
     591 {
     592
     593   /* The idea here is to strip the message/rfc822 part from its mail headers,
     594    * and store it in a file to resend to MM_extract_mime().
     595    */
     596
     597   char tmp[MAILTMPLEN];
     598   char *mailtext;
     599   char *content;
     600   char tmpfile[FILENAMELEN];
     601   time_t ti = time (0);
     602
     603
     604   if (pfx == NULL)                      /* If top level, is not inside a multipart */
     605     {
     606       /* pfx = (char *)malloc(STR_L);
     607       pfx = "";         */      /* Dummy prefix */
     608       /* The filename of the root node has to be redefined to the processed file */
     609       mailnode->file = (char *)malloc(FILENAME_LENGTH);
     610       sprintf(mailnode->file,"%s%d",EP_outputPrefix,mailnode->nodeID);
     611       if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "MAILNODE->FILE: %s",mailnode->file);
     612     }
     613
     614   /* Get the plain text contents of the message */
     615   mailtext = tmp;
     616   mailtext = mail_fetchtext(stream, 1);
     617
     618
     619   /* This buffer has to be dumped in a file from where it will be read by MM_extract_mime():
     620    * another stream will be opened, so the format of the file must be correct.
     621    * The LINELENGTH is to take the first 2 lines into account.
     622    */
     623
     624   content = (char *)malloc(2*LINELENGTH + strlen(mailtext) + 2);
     625   sprintf (content,"From dbase@whois.ripe.net %s",ctime (&ti));
     626   sprintf (content+strlen(content), "%s\n", mailtext);
     627
     628
     629   /* Generation of a temporary file:
     630    * The file must be unique inside the process. If we rewrite
     631    * on the same tmp file, which is used as a mailbox by c-client,
     632    * the c-client library has problems because it sees the mailbox changes
     633    * (I had problems with multipart/digest and message/rfc822).
     634    * "pass" is a global variable which increases every time we pass
     635    * through MM_extract_mime(): it should hence be unique each time
     636    * we call a driver.
     637    */
     638   sprintf (tmpfile,"%s.tmp.%ld",mailnode->file,pass);
     639   write_file(tmpfile,content,strlen(content));
     640
     641   MM_extract_mime(tmpfile, pfx, mailnode, debug);
     642
     643   /* Clean up... */
     644   free(content);
     645   remove(tmpfile);
     646
     647 }
     648
     649 void parse_multipart_alternative (MAILSTREAM *stream, BODY *body, char *pfx, EP_mail_node *mailnode)
         /* [<][>][^][v][top][bottom][index][help] */
     650 {
     651
     652   char tmppfx[MAILTMPLEN];
     653   char childpfx[MAILTMPLEN];
     654   char tmppart[MAILTMPLEN];
     655   /*   char *s = tmppfx; */
     656   EP_mail_node *newnode;
     657   EP_mail_node *parsednode;
     658   EP_mail_node *nextnode;
     659   long i;
     660   PART *part;
     661   char *result;
     662   char *content;
     663   unsigned long length;
     664   time_t ti = time (0);
     665   char tmpfile[FILENAMELEN];
     666   char nodefile[FILENAMELEN];
     667
     668
     669   if (debug >= 2)
     670     ER_dbg_va (FAC_MM, ASP_MM_GEN, "Bytes: %lu",body->size.bytes);
     671
     672   /* if not first time, extend prefix */
     673   if (pfx == NULL)
     674     {
     675       tmppfx[0] = '\0';
     676       pfx = tmppfx;
     677     }
     678
     679
     680   /* Initialize the first node: it is an inner node */
     681
     682   /* The tree height increases */
     683   EP_TreeHeight++;
     684
     685   /* The number of nodes increases */
     686   EP_Node_ID++;
     687
     688   sprintf (nodefile,"%s%d",EP_outputPrefix,EP_Node_ID);
     689   if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "inner-nodefile: %s",nodefile);
     690
     691   newnode = EP_InitializeNode(nodefile, EP_Node_ID);
     692   mailnode->inner = newnode;
     693
     694   for (i = 1,part = body->nested.part; part; part = part->next)
     695     {
     696       if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "i: %ld, pfx: %s",i,pfx);
     697       if (debug >= 3) ER_dbg_va (FAC_MM, ASP_MM_GEN, "MYDEBUG: pfx=%s, tmppfx=%s,",pfx,tmppfx);
     698       sprintf (tmppart,"%ld",i);
     699       result = mail_fetch_mime(stream, (long)1, tmppart, &length, (long)0);
     700       if (debug >= 3)
     701         {
     702           ER_dbg_va (FAC_MM, ASP_MM_GEN, "body->size.bytes: %lu",body->size.bytes);
     703           ER_dbg_va (FAC_MM, ASP_MM_GEN, "(&part->body)->size.bytes: %lu",(&part->body)->size.bytes);
     704           ER_dbg_va (FAC_MM, ASP_MM_GEN, "length: %lu",length);
     705         }
     706
     707
     708       /* This buffer has to be dumped in a file from where it will be read by MM_extract_mime():
     709        * another stream will be opened, so the format of the file must be correct.
     710        * The LINELENGTH is to take the first 2 lines into account
     711        */
     712       content = (char *)malloc(2*LINELENGTH + length + (&part->body)->size.bytes + 2);
     713       sprintf (content,"From dbase@whois.ripe.net %sMIME-Version: 1.0\n",ctime (&ti));
     714       /* snprintf (content+strlen(content), (size_t)(length + (&part->body)->size.bytes) + 2, "%s\n", result); */
     715       g_snprintf ((gchar *)(content+strlen(content)), (gulong)(length + (&part->body)->size.bytes) + 2, "%s\n", result);
     716
     717       if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "Result: \n---\n%s\n---\nEnd results.\n", content);
     718
     719       /* Generation of a temporary file:
     720        * The file must be unique inside the process. If we rewrite
     721        * on the same tmp file, which is used as a mailbox by c-client,
     722        * the c-client library has problems because it sees it changes
     723        * (I had problems with multipart/digest and message/rfc822).
     724        * "pass" is a global variable which increases every time we pass
     725        * through MM_extract_mime(): it should hence be unique each time
     726        * we call a driver.
     727        */
     728       sprintf (tmpfile,"%s.tmp.%ld",newnode->file,pass);
     729       write_file(tmpfile,content,strlen(content));
     730
     731       /* This is needed to extend the prefix */
     732       sprintf (childpfx,"%s%ld.",pfx,i);
     733       if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "childpfx: %s",childpfx);
     734       MM_extract_mime(tmpfile, childpfx, newnode, debug);
     735
     736       /* Clean up... */
     737       free(content);
     738       remove(tmpfile);
     739
     740       /* Initialize the next node (if it exists) */
     741
     742       if (part->next != NULL)
     743         {
     744           EP_Node_ID++;
     745           sprintf (nodefile,"%s%d",EP_outputPrefix,EP_Node_ID);
     746           if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "next-nodefile: %s",nodefile);
     747           nextnode = EP_InitializeNode(nodefile, EP_Node_ID);
     748           parsednode = newnode;
     749           newnode = nextnode;
     750           parsednode->next = newnode;
     751         }
     752
     753       i++;
     754
     755     }
     756
     757 } /* parse_multipart_alternative() */
     758
     759
     760 void parse_multipart_signed (MAILSTREAM *stream, BODY *body, char *pfx, EP_mail_node *mailnode)
         /* [<][>][^][v][top][bottom][index][help] */
     761 {
     762
     763   char tmppfx[MAILTMPLEN];
     764   char tmppart[MAILTMPLEN];
     765   EP_mail_node *newnode;
     766   PART *part;
     767   char *result;
     768   char *content;
     769   unsigned long length;
     770   char tmpfile[FILENAMELEN];
     771   char nodefile[FILENAMELEN];
     772   struct VerifySignObject vSO;
     773   /*  int retcode; */
     774
     775   if (debug >= 2)
     776     ER_dbg_va (FAC_MM, ASP_MM_GEN, "Bytes: %lu",body->size.bytes);
     777
     778
     779   /* if not first time, extend prefix */
     780   if (pfx == NULL)
     781     {
     782       tmppfx[0] = '\0';
     783       pfx = tmppfx;
     784     }
     785
     786
     787   /* Initialize the inner node */
     788
     789   /* The tree height increases */
     790   EP_TreeHeight++;
     791
     792   /* The number of nodes increases */
     793   EP_Node_ID++;
     794
     795   sprintf (nodefile,"%s%d",EP_outputPrefix,EP_Node_ID);
     796   if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "inner-nodefile: %s",nodefile);
     797
     798   newnode = EP_InitializeNode(nodefile, EP_Node_ID);
     799   mailnode->inner = newnode;
     800
     801   /* We give the same content-type to the child so as not to leave the default
     802      value (-1) */
     803   newnode->MIMEContentType = mailnode->MIMEContentType;
     804
     805   /* We must get the two parts of the message. The signed part
     806    * and the signature. There can't be more than two parts
     807    * (see RFC2015).
     808    */
     809
     810   if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "pfx: %s",pfx);
     811
     812   /* Signed part: it is the first part of the message. */
     813
     814   part = body->nested.part;
     815
     816   sprintf (tmppart,"%s1",tmppfx);
     817   if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "tmppart: %s",tmppart);
     818
     819   result = mail_fetch_mime(stream, (long)1, tmppart, &length, (long)0);
     820   if (debug >= 3)
     821     {
     822       ER_dbg_va (FAC_MM, ASP_MM_GEN, "body->size.bytes: %lu",body->size.bytes);
     823       ER_dbg_va (FAC_MM, ASP_MM_GEN, "(&part->body)->size.bytes: %lu",(&part->body)->size.bytes);
     824       ER_dbg_va (FAC_MM, ASP_MM_GEN, "length: %lu",length);
     825     }
     826
     827   /* The signed part must be dumped in a file together with the MIME headers */
     828
     829   content = (char *)malloc(length + (&part->body)->size.bytes + 2);
     830   snprintf (content,(size_t)(length + (&part->body)->size.bytes) + 2, "%s\n", result);
     831
     832   if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "Result: \n---\n%s\n---\nEnd results.\n", content);
     833
     834   if (debug) ER_dbg_va (FAC_MM, ASP_MM_GEN, "MSG file: %s",newnode->file);
     835   write_file(newnode->file,content,strlen(content));
     836
     837
     838   free(content);
     839
     840   /* Signature */
     841
     842   part = part->next;
     843   sprintf (tmppart,"%s2",tmppfx);
     844   if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "tmppart: %s",tmppart);
     845
     846   result = mail_fetch_mime(stream, (long)1, tmppart, &length, (long)0);
     847   if (debug >= 2)
     848     {
     849       ER_dbg_va (FAC_MM, ASP_MM_GEN, "body->size.bytes: %lu\n",body->size.bytes);
     850       ER_dbg_va (FAC_MM, ASP_MM_GEN, "(&part->body)->size.bytes: %lu\n",(&part->body)->size.bytes);
     851       ER_dbg_va (FAC_MM, ASP_MM_GEN, "length: %lu\n",length);
     852     }
     853
     854   /* The signature must be dumped _without_ MIME headers instead!
     855    * Check where is the "length" variable...
     856    */
     857
     858   content = (char *)malloc((&part->body)->size.bytes + 2);
     859
     860   snprintf (content,(size_t)((&part->body)->size.bytes) + 2, "%s\n", result + length);
     861
     862   if (debug >= 2) ER_dbg_va (FAC_MM, ASP_MM_GEN, "Result: \n---\n%s\n---\nEnd results.\n", content);
     863
     864   sprintf (tmpfile,"%s.sig",newnode->file);
     865   if (debug) ER_dbg_va (FAC_MM, ASP_MM_GEN, "SIG file: %s",tmpfile);
     866   write_file(tmpfile,content,strlen(content));
     867
     868   /* Calling the verification procedure */
     869
     870   strcpy(vSO.iDocSigFilename, newnode->file);
     871   strcpy(vSO.iSigFilename, tmpfile);
     872   strcpy(vSO.keyRing, EP_keyRing);
     873
     874   PA_VerifySignature(&vSO);
     875
     876   newnode->isValidPGPSignature = vSO.isValid;
     877   newnode->keyID= vSO.keyID;
     878
     879   EP_MIMEParse(newnode);
     880
     881   free(content);
     882   remove(tmpfile);
     883
     884
     885 } /* parse_multipart_signed */
     886
     887
     888
     889 /* MM status report
     890  * Accepts: MAIL stream
     891  */
     892
     893 void status (MAILSTREAM *stream)
         /* [<][>][^][v][top][bottom][index][help] */
     894 {
     895   long i;
     896   char date[MAILTMPLEN];
     897   rfc822_date (date);
     898   ER_dbg_va (FAC_MM, ASP_MM_GEN, "%s",date);
     899   if (stream)
     900     {
     901       if (stream->mailbox)
     902         {
     903           ER_dbg_va (FAC_MM, ASP_MM_GEN, " %s mailbox: %s",
     904                      stream->dtb->name,stream->mailbox);
     905           ER_dbg_va (FAC_MM, ASP_MM_GEN, " %lu messages, %lu recent",
     906                      stream->nmsgs,stream->recent);
     907         }
     908       else  ER_dbg_va (FAC_MM, ASP_MM_GEN, "% No mailbox is open on this stream");
     909       if (stream->user_flags[0])
     910         {
     911            ER_dbg_va (FAC_MM, ASP_MM_GEN, "Keywords: %s",stream->user_flags[0]);
     912           for (i = 1; i < NUSERFLAGS && stream->user_flags[i]; ++i)
     913            ER_dbg_va (FAC_MM, ASP_MM_GEN,", %s",stream->user_flags[i]);
     914           /* puts (""); */
     915         }
     916     }
     917 } /* status() */
     918
     919
     920 Mail_Header_Field *get_mail_hdr_field (MAILSTREAM *stream,
         /* [<][>][^][v][top][bottom][index][help] */
     921                                        long mesgno,
     922                                        STRINGLIST *cur,
     923                                        const char *hdr_title)
     924 {
     925
     926   char *tmphdr;
     927   char tmpline[MAXBUFSIZE];
     928   int i, j, c, tmpsize, titlesize;
     929   Mail_Header_Field *hdr_field;
     930   Mail_Header_Field *mhfp;
     931   Mail_Header_Field *newmhfp;
     932
     933   mhfp = hdr_field = newmhfp = NULL;
     934
     935   tmphdr = get_header_line(stream,mesgno,cur,hdr_title);
     936
     937   tmpsize = strlen(tmphdr);
     938
     939   /* Length of the header title plus ": "*/
     940   titlesize = strlen(hdr_title) + 2;
     941
     942   j = 0;
     943
     944   /* Get one line at a time, and put the header lines in the Mail Header Field */
     945
     946   for (i = 0; i < tmpsize; i++)
     947     {
     948       c = tmphdr[i];
     949       if (c == 10) /* EOL */
     950         {
     951           if ((j > 1) || ((mhfp == NULL) && (i == tmpsize - 1))) /* j>1 and not j>0 because "\r" is always read;
     952                                                                   * The second option is needed for
     953                                                                   * the empty headers */
     954             {
     955               newmhfp = (Mail_Header_Field *)malloc(sizeof(Mail_Header_Field));
     956               newmhfp->next = NULL;
     957               newmhfp->field = (char *)malloc(j + 2);
     958               if (j > 1)
     959                 /* We do not copy here the header title */
     960                 sprintf (newmhfp->field,"%s\n",tmpline + titlesize);
     961               else
     962                 sprintf (newmhfp->field,"\n");
     963
     964
     965               if (mhfp == NULL)
     966                 {
     967                   mhfp = newmhfp;
     968                   hdr_field = newmhfp;
     969                 }
     970               else
     971                 {
     972                   mhfp->next = newmhfp;
     973                   mhfp = newmhfp;
     974                 }
     975             }
     976           j = 0;
     977         }
     978       else
     979         {
     980           sprintf (tmpline + j++,"%c", c);
     981         }
     982
     983     }
     984
     985   free(tmphdr);
     986
     987   return (hdr_field);
     988
     989 } /* get_mail_hdr_field() */
     990
     991
     992
     993 char *get_header_line (MAILSTREAM *stream, long mesgno, STRINGLIST *cur, const char *hdr_title)
         /* [<][>][^][v][top][bottom][index][help] */
     994 {
     995
     996   unsigned long offset;
     997   size_t tmplength;
     998   char *curtmp;
     999   char *hdr_attr;
    1000   long a,b;
    1001
    1002
    1003   /* We need to insert the header title into a STRINGLIST structure, as
    1004    * this is the type that must be supplied to mail_fetchheader_full.
    1005    */
    1006
    1007   cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
    1008                                      cpystr (hdr_title)));
    1009
    1010   /* If we don't want to return the header title, but only the contents,
    1011    * this offset allows us to strip the header title. The "magic number" 2
    1012    * is the string ": " of the header.
    1013    * This method is uneffective for multiple headers (ex. Cc, Reply-To, etc.).
    1014    */
    1015
    1016   offset = cur->text.size + 2;
    1017
    1018   /* Get the header line, if it exists */
    1019
    1020   curtmp = mail_fetchheader_full (stream,mesgno,cur,NIL,NIL);
    1021
    1022   tmplength = strlen(curtmp);
    1023   hdr_attr = (char *)malloc(tmplength + 4);
    1024
    1025   /* cur contains the header title string, like "From:", "Subject:" etc.
    1026    * tmplength is the length of the corresponding header line extracted
    1027    * from the message. If a real line is returned, the header title
    1028    * ("From:", "Subject:" etc.) will be contained within, hence
    1029    * tmplength >= cur->text.size . This means that if
    1030    * (cur->text.size > tmplength), no such header is present in the mail:
    1031    * we must return an (almost) empty string.
    1032    */
    1033
    1034   a = (long)tmplength;
    1035   b = (long)cur->text.size;
    1036   if (a > b)
    1037     {
    1038       /* If we want to strip the header */
    1039       /*sprintf (hdr_attr,"%s",curtmp + offset); */
    1040       sprintf (hdr_attr,"%s",curtmp);
    1041       /* printf ("%s",hdr_attr); */
    1042     }
    1043   else
    1044     {
    1045       sprintf (hdr_attr,"\n\n");
    1046     }
    1047
    1048   return (hdr_attr);
    1049 } /* get_header_line() */
    1050
    1051
    1052
    1053
    1054 /* Subroutine for writing in a file */
    1055
    1056 void write_file (char *filename, char *text, size_t text_size)
         /* [<][>][^][v][top][bottom][index][help] */
    1057 {
    1058
    1059   FILE *fd;
    1060   size_t i;
    1061
    1062   /* printf ("%s\n",filename); */
    1063
    1064   if ((fd = fopen(filename,"w")) != NULL)
    1065     {
    1066       for (i = 0; i < text_size; i++)
    1067         if (text[i] != 13)
    1068           fprintf (fd, "%c",text[i]);
    1069       fclose(fd);
    1070     }
    1071   else
    1072     {
    1073       ER_perror(FAC_MM, MM_CANTOPEN, "%s for writing\n",filename);
    1074       die;
    1075     }
    1076
    1077 } /* write_file() */
    1078
    1079
    1080 void read_file (const char *filename)
         /* [<][>][^][v][top][bottom][index][help] */
    1081 {
    1082
    1083   FILE *fd;
    1084   int c;
    1085
    1086   if ((fd = fopen (filename,"r")) != NULL)
    1087     {
    1088       while ((c = getc(fd)) != EOF)
    1089         putc (c, stdout);
    1090       fclose (fd);
    1091     }
    1092   else
    1093     {
    1094       ER_perror(FAC_MM, MM_CANTOPEN, "%s for reading\n",filename);
    1095       die;
    1096     }
    1097
    1098 } /* read_file() */
    1099
    1100
    1101 void put_in_file (char *fileprefix, char *extension, char *text, size_t text_size)
         /* [<][>][^][v][top][bottom][index][help] */
    1102 {
    1103
    1104   char filename[FILENAMELEN];
    1105
    1106
    1107   /* Write in a file */
    1108
    1109   sprintf (filename,"%s-%s",fileprefix,extension);
    1110   /* printf ("%s\n",filename); */
    1111
    1112   write_file(filename,text,text_size);
    1113
    1114 }/* put_in_file() */
    1115
    1116
    1117 /* Stolen from which_keytypes.c and converted to use regex.h instead of libgen.h */
    1118
    1119
    1120 int do_regex_test (const char *pattern, char *string)
         /* [<][>][^][v][top][bottom][index][help] */
    1121 {
    1122
    1123   int match = 0;
    1124
    1125   /* These are not used, since REG_NOSUB is specified in regcomp() */
    1126   size_t nmatch = 0;
    1127   regmatch_t pmatch[1];
    1128
    1129   regex_t *re;
    1130
    1131   re = (regex_t *)malloc(STR_XL);
    1132
    1133   regcomp(re, pattern, REG_NOSUB || REG_NEWLINE);
    1134   if (regexec(re, string, nmatch, pmatch, 0))
    1135     match = 0;
    1136   else
    1137     match = 1;
    1138
    1139   regfree(re);
    1140
    1141   /* Caution! regfree() does not do this job... */
    1142   free(re);
    1143
    1144   return(match);
    1145
    1146 } /* do_regex_test() */
    1147
    1148
    1149 /* Interfaces to c-client.
    1150  * They must be here for the code to be compiled,
    1151  * but most can stay empty.
    1152  */
    1153
    1154 void mm_searched (MAILSTREAM *stream,unsigned long number)
         /* [<][>][^][v][top][bottom][index][help] */
    1155 {
    1156 }
    1157
    1158
    1159 void mm_exists (MAILSTREAM *stream,unsigned long number)
         /* [<][>][^][v][top][bottom][index][help] */
    1160 {
    1161 }
    1162
    1163
    1164 void mm_expunged (MAILSTREAM *stream,unsigned long number)
         /* [<][>][^][v][top][bottom][index][help] */
    1165 {
    1166 }
    1167
    1168
    1169 void mm_flags (MAILSTREAM *stream,unsigned long number)
         /* [<][>][^][v][top][bottom][index][help] */
    1170 {
    1171 }
    1172
    1173 void mm_notify (MAILSTREAM *stream,char *string,long errflg)
         /* [<][>][^][v][top][bottom][index][help] */
    1174 {
    1175 }
    1176
    1177 void mm_list (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
         /* [<][>][^][v][top][bottom][index][help] */
    1178 {
    1179 }
    1180
    1181 void mm_lsub (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
         /* [<][>][^][v][top][bottom][index][help] */
    1182 {
    1183 }
    1184
    1185 void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
         /* [<][>][^][v][top][bottom][index][help] */
    1186 {
    1187 }
    1188
    1189 void mm_log (char *string,long errflg)
         /* [<][>][^][v][top][bottom][index][help] */
    1190 {
    1191   switch ((short) errflg) {
    1192   case NIL:
    1193     ER_dbg_va (FAC_MM, ASP_MM_GEN, "[%s]",string);
    1194     break;
    1195   case PARSE:
    1196   case WARN:
    1197     ER_perror (FAC_MM, MM_WARNCCL, "%%%s",string);
    1198     break;
    1199   case ERROR:
    1200     ER_perror (FAC_MM, MM_ERRCCL, "%s",string);
    1201     break;
    1202   }
    1203 }
    1204
    1205 void mm_dlog (char *string)
         /* [<][>][^][v][top][bottom][index][help] */
    1206 {
    1207   puts (string);
    1208 }
    1209
    1210 void mm_login (NETMBX *mb,char *user,char *pwd,long trial)
         /* [<][>][^][v][top][bottom][index][help] */
    1211 {
    1212 }
    1213
    1214 void mm_critical (MAILSTREAM *stream)
         /* [<][>][^][v][top][bottom][index][help] */
    1215 {
    1216 }
    1217
    1218 void mm_nocritical (MAILSTREAM *stream)
         /* [<][>][^][v][top][bottom][index][help] */
    1219 {
    1220 }
    1221
    1222 long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
         /* [<][>][^][v][top][bottom][index][help] */
    1223 {
    1224 #if UNIXLIKE
    1225   kill (getpid (),SIGSTOP);
    1226 #else
    1227   abort ();
    1228 #endif
    1229   return NIL;
    1230 }
    1231
    1232 void mm_fatal (char *string)
         /* [<][>][^][v][top][bottom][index][help] */
    1233 {
    1234   ER_perror(FAC_MM, MM_FATCCL, "%s\n",string);
    1235   die;
    1236 }
    1237

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