## 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.29 $
       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,2002                       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, k, c, tmpsize, titlesize;
     925   int continuation = 0;
     926   Mail_Header_Field *hdr_field;
     927   Mail_Header_Field *mhfp;
     928   Mail_Header_Field *newmhfp;
     929
     930   mhfp = hdr_field = newmhfp = NULL;
     931
     932   tmphdr = get_header_line(stream,mesgno,cur,hdr_title);
     933
     934   tmpsize = strlen(tmphdr);
     935
     936   /* Length of the header title plus ":" */
     937   titlesize = strlen(hdr_title) + 1;
     938
     939   continuation = 0;   /* to detect continuation lines */
     940   j = 0;
     941   /* also initialize tmpline */
     942   for(i = 0; i < MAXBUFSIZE; i++){
     943     tmpline[i] = '\0';
     944   }
     945
     946   /* Get one line at a time, and put the header lines in the Mail Header Field */
     947
     948   for (i = 0; i < tmpsize; i++)
     949     {
     950       c = tmphdr[i];
     951       if (c == 10) /* EOL */
     952           {
     953             if ((j > 1) || ((mhfp == NULL) && (i == tmpsize - 1))) /* j>1 and not j>0 because "\r" is always read;
     954                                                                     * The second option is needed for
     955                                                                     * the empty headers */
     956             {
     957                 newmhfp = (Mail_Header_Field *)UT_malloc(sizeof(Mail_Header_Field));
     958                 newmhfp->next = NULL;
     959                 newmhfp->field = (char *)UT_malloc(j + 2);
     960                 if (j > 1)
     961             {
     962               if ( ! continuation )
     963                         /* We do not copy the header title from the first line */
     964                         sprintf (newmhfp->field,"%s\n",tmpline + titlesize);
     965               else
     966                         /* There is no header title on continuation lines */
     967                         sprintf (newmhfp->field,"%s\n",tmpline);
     968             }
     969                 else
     970                       sprintf (newmhfp->field,"\n");
     971
     972                 if (mhfp == NULL)
     973                     {
     974                       mhfp = newmhfp;
     975                       hdr_field = newmhfp;
     976                     }
     977                 else
     978                     {
     979                       mhfp->next = newmhfp;
     980                       mhfp = newmhfp;
     981                     }
     982             }
     983         continuation = 1;   /* next time we are reading continuation lines */
     984             j = 0;
     985         /* re-initialize tmpline */
     986         for (k = 0; k < MAXBUFSIZE; k++)
     987         {
     988           tmpline[k] = '\0';
     989         }
     990           }
     991       else
     992           {
     993             sprintf (tmpline + j++,"%c", c);
     994           }
     995     }
     996
     997   UT_free(tmphdr);
     998
     999   return (hdr_field);
    1000
    1001 } /* get_mail_hdr_field() */
    1002
    1003
    1004
    1005 char *get_header_line (MAILSTREAM *stream, long mesgno, STRINGLIST *cur, const char *hdr_title)
         /* [<][>][^][v][top][bottom][index][help] */
    1006 {
    1007
    1008   unsigned long offset;
    1009   size_t tmplength;
    1010   char *curtmp;
    1011   char *hdr_attr;
    1012   long a,b;
    1013
    1014
    1015   /* We need to insert the header title into a STRINGLIST structure, as
    1016    * this is the type that must be supplied to mail_fetchheader_full.
    1017    */
    1018
    1019   cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *)
    1020                                      cpystr (hdr_title)));
    1021
    1022   /* If we don't want to return the header title, but only the contents,
    1023    * this offset allows us to strip the header title. The "magic number" 2
    1024    * is the string ": " of the header.
    1025    * This method is uneffective for multiple headers (ex. Cc, Reply-To, etc.).
    1026    */
    1027
    1028   offset = cur->text.size + 2;
    1029
    1030   /* Get the header line, if it exists */
    1031
    1032   curtmp = mail_fetchheader_full (stream,mesgno,cur,NIL,NIL);
    1033
    1034   tmplength = strlen(curtmp);
    1035   hdr_attr = (char *)UT_malloc(tmplength + 4);
    1036
    1037   /* cur contains the header title string, like "From:", "Subject:" etc.
    1038    * tmplength is the length of the corresponding header line extracted
    1039    * from the message. If a real line is returned, the header title
    1040    * ("From:", "Subject:" etc.) will be contained within, hence
    1041    * tmplength >= cur->text.size . This means that if
    1042    * (cur->text.size > tmplength), no such header is present in the mail:
    1043    * we must return an (almost) empty string.
    1044    */
    1045
    1046   a = (long)tmplength;
    1047   b = (long)cur->text.size;
    1048   if (a > b)
    1049     {
    1050       /* If we want to strip the header */
    1051       /*sprintf (hdr_attr,"%s",curtmp + offset); */
    1052       sprintf (hdr_attr,"%s",curtmp);
    1053       /* printf ("%s",hdr_attr); */
    1054     }
    1055   else
    1056     {
    1057       sprintf (hdr_attr,"\n\n");
    1058     }
    1059
    1060   return (hdr_attr);
    1061 } /* get_header_line() */
    1062
    1063
    1064
    1065
    1066 /* Subroutine for writing in a file */
    1067
    1068 void write_file (char *filename, char *text, size_t text_size)
         /* [<][>][^][v][top][bottom][index][help] */
    1069 {
    1070
    1071   FILE *fd;
    1072   size_t i;
    1073
    1074   /* printf ("%s\n",filename); */
    1075
    1076   if ((fd = fopen(filename,"w")) != NULL)
    1077     {
    1078       for (i = 0; i < text_size; i++)
    1079         if (text[i] != 13)
    1080           fprintf (fd, "%c",text[i]);
    1081       fclose(fd);
    1082     }
    1083   else
    1084     {
    1085       ER_perror(FAC_MM, MM_CANTOPEN, "%s for writing\n",filename);
    1086       die;
    1087     }
    1088
    1089 } /* write_file() */
    1090
    1091
    1092 void read_file (const char *filename)
         /* [<][>][^][v][top][bottom][index][help] */
    1093 {
    1094
    1095   FILE *fd;
    1096   int c;
    1097
    1098   if ((fd = fopen (filename,"r")) != NULL)
    1099     {
    1100       while ((c = getc(fd)) != EOF)
    1101         putc (c, stdout);
    1102       fclose (fd);
    1103     }
    1104   else
    1105     {
    1106       ER_perror(FAC_MM, MM_CANTOPEN, "%s for reading\n",filename);
    1107       die;
    1108     }
    1109
    1110 } /* read_file() */
    1111
    1112
    1113 void put_in_file (char *fileprefix, char *extension, char *text, size_t text_size)
         /* [<][>][^][v][top][bottom][index][help] */
    1114 {
    1115
    1116   char filename[FILENAMELEN];
    1117
    1118
    1119   /* Write in a file */
    1120
    1121   sprintf (filename,"%s-%s",fileprefix,extension);
    1122   /* printf ("%s\n",filename); */
    1123
    1124   write_file(filename,text,text_size);
    1125
    1126 }/* put_in_file() */
    1127
    1128
    1129 /* Stolen from which_keytypes.c and converted to use regex.h instead of libgen.h */
    1130
    1131
    1132 int do_regex_test (const char *pattern, char *string)
         /* [<][>][^][v][top][bottom][index][help] */
    1133 {
    1134
    1135   int match = 0;
    1136
    1137   /* These are not used, since REG_NOSUB is specified in regcomp() */
    1138   size_t nmatch = 0;
    1139   regmatch_t pmatch[1];
    1140
    1141   regex_t *re;
    1142
    1143   re = (regex_t *)UT_malloc(STR_XL);
    1144
    1145   regcomp(re, pattern, REG_NOSUB || REG_NEWLINE);
    1146   if (regexec(re, string, nmatch, pmatch, 0))
    1147     match = 0;
    1148   else
    1149     match = 1;
    1150
    1151   regfree(re);
    1152
    1153   /* Caution! regfree() does not do this job... */
    1154   UT_free(re);
    1155
    1156   return(match);
    1157
    1158 } /* do_regex_test() */
    1159
    1160
    1161 /* Interfaces to c-client.
    1162  * They must be here for the code to be compiled,
    1163  * but most can stay empty.
    1164  */
    1165
    1166 void mm_searched (MAILSTREAM *stream,unsigned long number)
         /* [<][>][^][v][top][bottom][index][help] */
    1167 {
    1168 }
    1169
    1170
    1171 void mm_exists (MAILSTREAM *stream,unsigned long number)
         /* [<][>][^][v][top][bottom][index][help] */
    1172 {
    1173 }
    1174
    1175
    1176 void mm_expunged (MAILSTREAM *stream,unsigned long number)
         /* [<][>][^][v][top][bottom][index][help] */
    1177 {
    1178 }
    1179
    1180
    1181 void mm_flags (MAILSTREAM *stream,unsigned long number)
         /* [<][>][^][v][top][bottom][index][help] */
    1182 {
    1183 }
    1184
    1185 void mm_notify (MAILSTREAM *stream,char *string,long errflg)
         /* [<][>][^][v][top][bottom][index][help] */
    1186 {
    1187 }
    1188
    1189 void mm_list (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
         /* [<][>][^][v][top][bottom][index][help] */
    1190 {
    1191 }
    1192
    1193 void mm_lsub (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
         /* [<][>][^][v][top][bottom][index][help] */
    1194 {
    1195 }
    1196
    1197 void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
         /* [<][>][^][v][top][bottom][index][help] */
    1198 {
    1199 }
    1200
    1201 void mm_log (char *string,long errflg)
         /* [<][>][^][v][top][bottom][index][help] */
    1202 {
    1203   switch ((short) errflg) {
    1204   case NIL:
    1205     ER_dbg_va (FAC_MM, ASP_MM_GEN, "[%s]",string);
    1206     break;
    1207   case PARSE:
    1208   case WARN:
    1209     ER_perror (FAC_MM, MM_WARNCCL, "%%%s",string);
    1210     break;
    1211   case ERROR:
    1212     ER_perror (FAC_MM, MM_ERRCCL, "%s",string);
    1213     break;
    1214   }
    1215 }
    1216
    1217 void mm_dlog (char *string)
         /* [<][>][^][v][top][bottom][index][help] */
    1218 {
    1219   puts (string);
    1220 }
    1221
    1222 void mm_login (NETMBX *mb,char *user,char *pwd,long trial)
         /* [<][>][^][v][top][bottom][index][help] */
    1223 {
    1224 }
    1225
    1226 void mm_critical (MAILSTREAM *stream)
         /* [<][>][^][v][top][bottom][index][help] */
    1227 {
    1228 }
    1229
    1230 void mm_nocritical (MAILSTREAM *stream)
         /* [<][>][^][v][top][bottom][index][help] */
    1231 {
    1232 }
    1233
    1234 long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
         /* [<][>][^][v][top][bottom][index][help] */
    1235 {
    1236 #if UNIXLIKE
    1237   kill (getpid (),SIGSTOP);
    1238 #else
    1239   abort ();
    1240 #endif
    1241   return NIL;
    1242 }
    1243
    1244 void mm_fatal (char *string)
         /* [<][>][^][v][top][bottom][index][help] */
    1245 {
    1246   ER_perror(FAC_MM, MM_FATCCL, "%s\n",string);
    1247   die;
    1248 }
    1249

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