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

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