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] */