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,
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(
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 (
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)
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)
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)
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)
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)
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)
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)
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, 
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)
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)
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)
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)
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)
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)
1172 | {
1173 | }
1174 | 
1175 | 
1176 | void mm_exists (MAILSTREAM *stream,unsigned long number)
1177 | {
1178 | }
1179 | 
1180 | 
1181 | void mm_expunged (MAILSTREAM *stream,unsigned long number)
1182 | {
1183 | }
1184 | 
1185 | 
1186 | void mm_flags (MAILSTREAM *stream,unsigned long number)
1187 | {
1188 | }
1189 | 
1190 | void mm_notify (MAILSTREAM *stream,char *string,long errflg)
1191 | {
1192 | }
1193 | 
1194 | void mm_list (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
1195 | {
1196 | }
1197 | 
1198 | void mm_lsub (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
1199 | {
1200 | }
1201 | 
1202 | void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
1203 | {
1204 | }
1205 | 
1206 | void mm_log (char *string,long errflg)
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)
1223 | {
1224 |   puts (string);
1225 | }
1226 | 
1227 | void mm_login (NETMBX *mb,char *user,char *pwd,long trial)
1228 | {
1229 | }
1230 | 
1231 | void mm_critical (MAILSTREAM *stream)
1232 | {
1233 | }
1234 | 
1235 | void mm_nocritical (MAILSTREAM *stream)
1236 | {
1237 | }
1238 | 
1239 | long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
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)
1250 | {
1251 |   ER_perror(FAC_MM, MM_FATCCL, "%s\n",string);
1252 |   die;
1253 | }
1254 |