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