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

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