## modules/mm/mm.c

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

## DEFINITIONS

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

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