modules/mm/mm.c

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

FUNCTIONS

This source file includes following functions.
  1. MM_decode
  2. MM_store
  3. MM_cleanup
  4. mm
  5. get_body_info
  6. status
  7. MM_bs_list_init
  8. MM_bs_list_ins_last
  9. MM_bs_list_cleanup
  10. MM_xmp_list_init
  11. MM_xmp_list_ins_last
  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: 1.12 $
   3 
   4   mm - MIME Parser module. Functions to parse a mail message,
   5   find if it is MIME-encapsulated, and return the parts of
   6   the message which are supported by the UP module.
   7 
   8   Status: NOT REVUED 
   9 
  10   Design and implementation by: Daniele Arena
  11 
  12   ******************/ /******************
  13   Copyright (c) 2000                              RIPE NCC
  14  
  15   All Rights Reserved
  16   
  17   Permission to use, copy, modify, and distribute this software and its
  18   documentation for any purpose and without fee is hereby granted,
  19   provided that the above copyright notice appear in all copies and that
  20   both that copyright notice and this permission notice appear in
  21   supporting documentation, and that the name of the author not be
  22   used in advertising or publicity pertaining to distribution of the
  23   software without specific, written prior permission.
  24   
  25   THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  26   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
  27   AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  28   DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  29   AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  30   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  31   ***************************************/
  32 
  33 /* Parts of this code stolen from mtest.c, 
  34  * part of the IMAP toolkit by Mark Crispin
  35  */
  36 
  37 /* Original version Copyright 1988 by The Leland Stanford Junior University
  38  * Copyright 1999 by the University of Washington
  39  *
  40  *  Permission to use, copy, modify, and distribute this software and its
  41  * documentation for any purpose and without fee is hereby granted, provided
  42  * that the above copyright notices appear in all copies and that both the
  43  * above copyright notices and this permission notice appear in supporting
  44  * documentation, and that the name of the University of Washington or The
  45  * Leland Stanford Junior University not be used in advertising or publicity
  46  * pertaining to distribution of the software without specific, written prior
  47  * permission.  This software is made available "as is", and
  48  * THE UNIVERSITY OF WASHINGTON AND THE LELAND STANFORD JUNIOR UNIVERSITY
  49  * DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE,
  50  * INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  51  * FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE UNIVERSITY OF
  52  * WASHINGTON OR THE LELAND STANFORD JUNIOR UNIVERSITY BE LIABLE FOR ANY
  53  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  54  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
  55  * CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF
  56  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  57  *
  58  */
  59 
  60 
  61 
  62 /* Standard headers */
  63 #include <stdio.h>
  64 #include <signal.h>
  65 #include <string.h>
  66 #include <sys/time.h>
  67 #include <sys/types.h>
  68 #include <regex.h>
  69 
  70 
  71 
  72 /* This is the local header */
  73 #include "mm.h"
  74 
  75 
  76 /* Comments about this module:
  77 
  78    - Still need to free() the allocated chunks. This is not strictly necessary,
  79      as this module will be called each time from anew and then will bail out,
  80      so all the memory will be freed anyway.
  81      But for the sake of cleanness, this needs to be done.
  82    - A good idea would be to use glib for allocations, linked lists etc.
  83      This still needs to be done.
  84    - Comments to be added.
  85    - Cleanup of internal functions.
  86    - printfs should be replaced with calls to ER module
  87 
  88    */
  89 
  90 
  91 
  92 /***************************************
  93  *
  94  * API functions
  95  *
  96  ***************************************/
  97 
  98 /* MM_decode. The main API function:
  99    it parses the file mail_file, at the message mesgno,
 100    and returns a structure pointing to files containing 
 101    all the different MIME parts, plus more information.
 102    It also returns some headers of the message.
 103 */
 104 
 105 int MM_decode (
     /* [<][>][^][v][top][bottom][index][help] */
 106                char *mail_file,                 /* filename of the "mailbox" */
 107                MM_header *mail_header,          /* Headers: to be returned */
 108                MM_xmp_list *part_list,          /* List of MIME parts: to be returned */
 109                long mesgno,                     /* Message number in the mailbox */
 110                long debug                       /* debug level */
 111                )
 112 {
 113 
 114   MAILSTREAM *stream = NULL;            /* MAILSTREAM is defined in c-client */
 115   char tmp[MAILTMPLEN];                 /* MAILTMPLEN is set in c-client */
 116   int mm_retcode;                       /* return code of the subroutine */
 117 
 118 
 119 #include "linkage.c"            /* c-client requires it to be included... */
 120   
 121 
 122   sprintf (tmp, "%s", mail_file);
 123   
 124   /* open mailbox and get the mail stream */
 125   stream = mail_open (stream,tmp,debug ? OP_DEBUG : NIL);
 126   
 127   
 128   /* Process the stream */
 129   if (!stream)
 130     {
 131       printf ("Invalid mailbox: %s\n", mail_file);
 132       return (1);
 133     }
 134   else
 135     {
 136 
 137       if (debug)
 138         {
 139           printf ("------------------ Message status:\n");
 140           status (stream);                      /* report message status */
 141           printf ("------------------ End of message status\n");
 142           if (debug >= 2) 
 143             printf ("================== DEBUG: Calling mm function...\n");
 144         }
 145 
 146       /* run "user interface" */
 147       mm_retcode = mm (stream,mail_header,part_list,mesgno,debug);      
 148 
 149       /* This doesn't work... It should free the memory allocated to the stream,
 150        * but if you run the program in a loop, at the second time it coredumps.
 151        * Seems like it wants to re-use the stream?
 152        * This should be investigated.
 153        */
 154       /* mail_close(stream); */
 155 
 156 
 157       return (mm_retcode);
 158     }
 159 
 160   /* We should never get here... */
 161   /* return(1); */
 162 
 163 } /* MM_decode() */
 164 
 165 
 166 /*********************************************/
 167 
 168 
 169 /* MM_store. Store stdin in a file. */
 170 
 171 int MM_store (char *source_file, char *destination_file, long debug)
     /* [<][>][^][v][top][bottom][index][help] */
 172 {
 173 
 174 
 175 #define LINESIZE STR_S
 176 #define REGEXP "^From "
 177 #define FIRSTCHARS 10
 178 
 179   int c;
 180   /* Input file pointer - Output file pointer */
 181   FILE *ifp;
 182   FILE *ofp;
 183   FILE *actualfile; /* Actual "file" to be opened (can be stdin) */
 184   time_t ti = time (0);
 185   char line[LINESIZE];
 186   char *tmpstr;
 187   int linechars = 0;
 188   int i;
 189   short charcount = 0;
 190   char firstline[LINESIZE];
 191   short using_file = 0;
 192 
 193 
 194   /* Check if we need to parse a file or stdin.
 195    * We parse stdin if source_file is "-" . 
 196    */
 197 
 198   if (strcmp(source_file,"-"))
 199     {
 200       if ((ifp = fopen(source_file,"r")) != NULL)
 201         {
 202           if (debug >= 3 ) printf ("Using file %s...\n",source_file);
 203           actualfile = ifp;
 204           using_file = 1;
 205         }
 206       else
 207         {
 208           printf ("ERROR: Could not open file %s for reading\n",source_file);
 209           return(1);
 210         }
 211     }
 212   else
 213     {
 214       if (debug >= 3 ) printf ("Using stdin...\n");
 215       actualfile = stdin;
 216     }
 217 
 218   if ((ofp = fopen(destination_file,"w")) != NULL)
 219     {
 220       /* fprintf (ofp,"From dbase@whois.ripe.net %s",ctime (&ti)); */
 221       
 222       /* This works. However, it can't be used since there is 
 223          no line length limitation in e-mail messages... 
 224          I leave it here if someone in the future has a better idea to do the trick.:) */
 225       /* while (tmpstr = fgets(line, LINESIZE, stdin))
 226          {
 227          if (do_regex_test(REGEXP,tmpstr)) fprintf (ofp,">");
 228          fputs (line,ofp);
 229          } */
 230         
 231       /* A non-trivial file dump from stdin.
 232          The problem here is that we need to store 
 233          the beginning of each line to check if
 234          the line starts with "From", in order to escape it with a ">".
 235          The string-only method cannot be used, for mail messages don't have
 236          a limit in line length 
 237          (we cannot use "gets" for buffer overflow risks).
 238          Thus we need to use a "mixed" method,
 239          grabbing the first "LINESIZE" characters in a string to check with
 240          regexp. This string is then dumped. All the characters not
 241          at the beginning of the string are directly dumped with putc. */
 242 
 243       /* This is not a very generic algorithm... 
 244          It is only fit when you are looking
 245          for a match at the beginning of a line. 
 246          BTW, the LINESIZE should be bigger
 247          than the regexp you are trying to match... 
 248          And: it only starts to work at the second line of the text... 
 249          Basically, it's ugly but it fits our needs. */
 250 
 251       /* Reset string */
 252       for (i = 0; i < LINESIZE; i++)
 253         firstline[i] = 0;
 254 
 255 
 256       while ((c = getc(actualfile)) != EOF)
 257         {
 258           /* This is done to write the file so that it can be 
 259              interpreted by c-client as a mailbox in "unix" format:
 260              the first line must start with "From " */
 261 
 262           /* Get first characters to see if the first line is a "^From " line */
 263           if (charcount < FIRSTCHARS)
 264             {
 265               firstline[charcount] = c;
 266               charcount++;
 267               continue;
 268             }
 269           if (charcount == FIRSTCHARS)
 270             {
 271               /* If the first line is not a "^From " line, put a fake one */
 272               if (!do_regex_test(REGEXP,firstline))
 273                   fprintf (ofp,"From dbase@whois.ripe.net %s",ctime (&ti));
 274               charcount++; /* otherwise it executes this block forever */
 275               fprintf (ofp,"%s",firstline); /* dump all the string anyway */
 276             }
 277 
 278 
 279           /* Work with the rest of the message */
 280           if ((c == 10) ||                      /* new line or */
 281               (linechars >= LINESIZE))          /* defined string length passed */
 282             {
 283               /* If there is a string in the buffer, the string is full or we have
 284                  a new line. We have to:
 285                  - check for the regexp
 286                  - dump the string in the file 
 287                  - reset the string */
 288               if (linechars)
 289                 {
 290                   tmpstr = line;
 291                   if (do_regex_test(REGEXP,tmpstr))     /* got regexp: */
 292                     fprintf (ofp,">");                          /* Escape the line */
 293                   fprintf (ofp,"%s",line);                      /* dump string anyway */
 294 
 295                   /* Reset string */
 296                   linechars = 0;
 297                   for (i = 0; i < LINESIZE; i++)
 298                     line[i] = 0;
 299                 }
 300               
 301               /* If we are at a new line, then start to get the string */
 302               if (c == 10)
 303                 linechars = 1;
 304               putc (c,ofp);     /* Dump the character anyway */
 305             }
 306           else if (linechars)           /* We are getting the string */
 307             {
 308               sprintf (line+linechars-1,"%c",c);
 309               linechars++;
 310             }
 311           else                          /* Too far from the start of the line: */
 312             putc (c,ofp);               /* We just dump the character to the file */
 313         } 
 314       fclose(ofp);
 315       if (using_file) fclose(ifp);
 316       return(0);
 317     }
 318   else
 319     {
 320       printf ("Error: couldn't open file %s for writing\n",destination_file);
 321       return(1);
 322     }
 323 } /* MM_store() */
 324 
 325 
 326 /*********************************************/
 327 
 328 /* MM_cleanup. Cleans the files containing the MIME parts
 329    when they're not needed anymore.
 330    Todo: also clean memory. */
 331 
 332 void MM_cleanup (MM_xmp_list *part_list, long debug)
     /* [<][>][^][v][top][bottom][index][help] */
 333 {
 334   MM_xmp *p;
 335   MM_xmp *q;
 336 
 337   for (p = part_list->head; p != NULL; p = q)
 338     {
 339       q = p->next;
 340       if (debug) printf ("Removing file %s...\n",p->file);
 341       remove(p->file);
 342       free(p->number);
 343       free(p->type);
 344       free(p->file);
 345       free(p);
 346     }
 347 
 348 } /* MM_cleanup() */
 349 
 350 
 351 
 352 
 353 /***************************************
 354  *
 355  * End of API functions
 356  *
 357  ***************************************/
 358 
 359 
 360 
 361 /* User interface */
 362 
 363 int mm (MAILSTREAM *stream, MM_header *hdr, MM_xmp_list *part_list, long mesgno, long debug)
     /* [<][>][^][v][top][bottom][index][help] */
 364 {
 365 
 366   char *section;
 367   char *result;
 368   char tmp[MAILTMPLEN];
 369   char strtmp[MAILTMPLEN];
 370   char *mailtext;
 371   unsigned long length;
 372   long flags;
 373   BODY *body;
 374   STRINGLIST *lines;
 375   STRINGLIST *cur;
 376   char fileprefix[FILENAMELEN];
 377   struct timeval *currenttime;
 378   pid_t proc_id;
 379   MM_b_section *secptr;
 380   MM_bs_list *section_list;
 381   MM_b_section *tmpsecptr;
 382   char *tmpsection;
 383   MM_xmp *newpart;
 384   int retcode = 0;
 385 
 386 
 387   /* Initialize the list of the body sections */
 388 
 389   section_list = (MM_bs_list *)malloc(sizeof(MM_bs_list));
 390   MM_bs_list_init (section_list);
 391   
 392   /* Create the filename prefix for the output files */
 393   
 394   currenttime = (struct timeval *)malloc(sizeof(struct timeval));
 395   if (!gettimeofday(currenttime,NIL))
 396     {
 397       if (proc_id = getpid())
 398         {
 399           sprintf (fileprefix,"%s/%s.%ld-%d",TEMPDIR,GLOBALPREFIX,currenttime->tv_sec,(int)proc_id);
 400         }
 401       else printf ("ERROR: could not get Process ID\n");
 402     }
 403   else printf ("ERROR: Could not gettimeofday\n");
 404   free(currenttime);
 405 
 406 
 407   if (mesgno && (mesgno <= stream->nmsgs)) 
 408     {
 409 
 410       /* Get the headers we need. */
 411       
 412       if (debug >= 2) printf ("================== DEBUG: my headers\n");
 413       
 414       
 415       lines = mail_newstringlist ();      
 416       cur = lines;
 417       
 418       /* Get information about the mentioned lines in the header */
 419       
 420       hdr->from = get_header_line(stream,mesgno,cur,"From");
 421       
 422       hdr->subject = get_header_line(stream,mesgno,cur,"Subject");
 423       
 424       hdr->date = get_header_line(stream,mesgno,cur,"Date");
 425       
 426       hdr->message_id = get_header_line(stream,mesgno,cur,"Message-ID");
 427       
 428       hdr->reply_to = get_header_line(stream,mesgno,cur,"Reply-To");
 429       
 430       hdr->cc = get_header_line(stream,mesgno,cur,"Cc");
 431       
 432       mail_free_stringlist (&lines);
 433       
 434       if (debug >= 2) printf ("================== DEBUG: After getting headers\n");
 435       
 436       
 437       
 438       if (debug) printf ("Message number: %lu. Total messages: %lu\n", mesgno, stream->nmsgs);
 439       
 440       
 441       /* Get structure of the message: body 
 442          (and envelope, which is unused) */
 443 
 444       if (debug >= 2) 
 445         printf ("================== DEBUG: Calling mail_fetchstructure...\n");
 446       mail_fetchstructure (stream,mesgno,&body);
 447 
 448 
 449       if (debug >= 2) 
 450         printf ("================== DEBUG: Printing body information...\n");
 451 
 452       if (body) 
 453         {
 454           /*printf ("Body encoding: %d (%s)\n", body->encoding, body_encodings[body->encoding]);*/
 455 
 456           /* 
 457            * Switch by supported body types.
 458            * The supported body types are:
 459            * - discrete:
 460            * text/plain
 461            * application/pgp
 462            * application/pgp-signature (inside multipart/signed)
 463            * - composite:
 464            * multipart/mixed
 465            * multipart/alternative
 466            * multipart/signed
 467            */
 468           if (debug >= 2) printf ("================== DEBUG: Calling get_body_info...\n");
 469           get_body_info (body,NIL,(long) 0, section_list, debug);
 470           if (debug >= 2) printf ("================== DEBUG: After get_body_info...\n");
 471                       
 472           secptr = section_list->head;
 473 
 474           if (debug >= 3)
 475             {
 476               printf ("================== DEBUG 3: number: %s\n",secptr->number);
 477               printf ("================== DEBUG 3: type: %s\n",secptr->type);
 478             }
 479 
 480 
 481 
 482           switch (body->type)
 483             {
 484 
 485             case TYPETEXT:
 486               mailtext = tmp;
 487               if ((body->subtype) && (!strcmp(body->subtype,"PLAIN")))
 488                 {
 489 
 490                   /* Can this explode with huge messages? */
 491                   mailtext = mail_fetchtext(stream,mesgno);
 492 
 493                   if (debug >= 3)
 494                     {
 495                       printf ("Type text/plain\n");
 496                       printf ("Message contents:\n");
 497                       printf ("%s\n",mailtext); 
 498                     }
 499 
 500                   secptr->supported = 1;
 501 
 502                 }
 503               else
 504                 {
 505                   sprintf (mailtext,"Unsupported content type: %s",
 506                           body_types[body->type]);
 507                   if (body->subtype) sprintf (mailtext+strlen(mailtext),"/%s\n",body->subtype);
 508                   /* printf ("%s",mailtext); */
 509                   secptr->supported = 0;
 510                 }
 511 
 512                   /* Write in a file */
 513                   
 514                   put_in_file (fileprefix,"1",mailtext,strlen(mailtext));
 515 
 516               break;
 517 
 518             case TYPEAPPLICATION:
 519 
 520               mailtext = tmp;
 521               if ((body->subtype) && (!strcmp(body->subtype,"PGP")))
 522                 {
 523                   mailtext = mail_fetchtext(stream,mesgno);
 524 
 525                   /* printf ("Type application/pgp\n");
 526                      printf ("Message contents:\n");
 527                      printf ("%s\n",mailtext); */
 528 
 529                   secptr->supported = 1;
 530 
 531                 }
 532               else
 533                 {
 534                   sprintf (mailtext,"Unsupported content type: %s",
 535                           body_types[body->type]);
 536                   if (body->subtype) sprintf (mailtext+strlen(mailtext),"/%s\n",body->subtype);
 537                   /* printf ("%s",mailtext); */
 538                   secptr->supported = 0;
 539                 }
 540 
 541               /* Write in a file */
 542               
 543               put_in_file (fileprefix,"1",mailtext,strlen(mailtext));
 544 
 545               break;
 546 
 547             case TYPEMULTIPART:
 548               if (body->subtype)
 549                 {
 550                   if ((!strcmp(body->subtype,"MIXED")) || (!strcmp(body->subtype,"ALTERNATIVE")) || (!strcmp(body->subtype,"SIGNED")))
 551                     {
 552                       /* printf ("Supported content type: %s/%s\n",body_types[body->type],body->subtype); */
 553                       
 554                       
 555                       flags = 0;
 556                       if (debug) printf ("Sections:\n");
 557                       while (secptr != NULL)
 558                         {
 559                           section = secptr->number;
 560                           if (debug) 
 561                             {
 562                               printf("++++++++++++++++++++++++++++++++++++++++++++\n");
 563                               printf ("%s\n",section);
 564                             }
 565                           /*printf ("%s\n",secptr->type);*/
 566                           
 567                           if ((!strcmp(secptr->type,"TEXT/PLAIN")) || (!strcmp(secptr->type,"APPLICATION/PGP-SIGNATURE")))
 568                             {
 569                               secptr->supported = 1;
 570                               result = mail_fetch_mime (stream, mesgno, section, &length, flags);
 571                               
 572                               
 573                               if (debug) 
 574                                 {
 575                                   printf ("Supported content type: %s\n",secptr->type);
 576                                   printf ("Length: %lu . Result: \n",length);
 577                                 }
 578                               
 579                               /* secptr->size: size of the contents of the body part.
 580                                  length: size of the MIME header of the body part. */
 581                               
 582                               secptr->mime_headers = (char *)malloc(length);
 583                               
 584                               strncpy(secptr->mime_headers,result,(size_t)length);
 585                               
 586                               /* printf ("--MIME headers:\n%s\n--End of MIME headers\n",secptr->mime_headers); */
 587                               
 588                               secptr->contents = (char *)malloc(secptr->size);
 589                               
 590                               strncpy(secptr->contents,result + length,(size_t)secptr->size);
 591 
 592                               /* Write in a file */
 593 
 594                               put_in_file (fileprefix,section,secptr->contents,secptr->size);
 595                               
 596                             }
 597                           else
 598                             {
 599                               sprintf (strtmp,"Unsupported content type: %s\n",secptr->type);
 600                               secptr->supported = 0;
 601                               /* printf ("%s",strtmp); */
 602                               /* Write in a file */
 603                               put_in_file (fileprefix,section,strtmp,strlen(strtmp));
 604                             }
 605                           
 606                           
 607                           printf ("\n\n");
 608                           
 609                           
 610                           
 611                           secptr = secptr->next;
 612                         }
 613                     }
 614                   else
 615                     {
 616                       sprintf (strtmp,"Unsupported content type: %s/%s\n",body_types[body->type],body->subtype);
 617                       secptr->supported = 0;
 618                       /* printf ("%s",strtmp); */
 619                       /* Write in a file */
 620                       put_in_file (fileprefix,"1",strtmp,strlen(strtmp));
 621                       /* Problem here - the notice is only written in the first file.
 622                          It is right, for we only should have one file for multipart/unsupported.
 623                          But from get_body_info, section_list is composed of all the parts
 624                          anyway...
 625                          a solution is to reduce here section_list to only one member,
 626                          as follows. */
 627                       secptr->next = NULL;
 628                       section_list->size = 1;
 629 
 630                     }
 631                 }
 632               else
 633                 {
 634 
 635                   /* In current c-client implementation, we _should_ never get here,
 636                      since the subtype "unknown" is added if no subtype is
 637                      specified. */
 638 
 639                   sprintf (strtmp,"Unknown multipart subtype\n");
 640                   secptr->supported = 0;
 641                   /* printf ("%s",strtmp); */
 642                   /* Write in a file */
 643                   put_in_file (fileprefix,"1",strtmp,strlen(strtmp));
 644                   /* Same problem here as above: the notice is
 645                      only written in the first file. We reduce the list to
 646                      a single member. */
 647                   secptr->next = NULL;
 648                   section_list->size = 1;
 649 
 650                 }
 651 
 652               break;
 653 
 654             default:
 655               sprintf (strtmp,"Unsupported content type: %s",body_types[body->type]);
 656               secptr->supported = 0;
 657               if (body->subtype) sprintf (strtmp+strlen(strtmp),"/%s\n",body->subtype);
 658               
 659               /* printf ("%s",strtmp); */
 660 
 661               /* Write in a file */
 662               put_in_file (fileprefix,"1",strtmp,strlen(strtmp));
 663               break;
 664             }
 665 
 666 
 667           /* Copy the relevant information to the structure used
 668              by the API, MM_xmp */
 669 
 670           tmpsecptr = section_list->head;
 671           
 672           while (tmpsecptr != NULL)
 673             {
 674 
 675               newpart = (MM_xmp *)malloc(sizeof(MM_xmp));
 676 
 677               tmpsection = tmpsecptr->number;
 678 
 679               newpart->number = (char *)malloc(strlen(tmpsection) + 1);
 680               sprintf (newpart->number,"%s",tmpsection);
 681               newpart->file = (char *)malloc(strlen(fileprefix) + strlen(tmpsection) + 2);
 682               sprintf (newpart->file,"%s-%s",fileprefix,tmpsection);
 683               newpart->type = (char *)malloc(strlen(tmpsecptr->type));
 684               sprintf (newpart->type,"%s",tmpsecptr->type);
 685               /* printf ("%s\n",newpart->number);
 686                  printf ("%s\n",newpart->file);
 687                  if (debug) printf ("Reading file %s...\n",newpart->file);
 688                  read_file(newpart->file); */
 689 
 690               newpart->supported = tmpsecptr->supported;
 691               /* printf("Supported: %hd\n",newpart->supported); */
 692 
 693               MM_xmp_list_ins_last(part_list, newpart);
 694               tmpsecptr = tmpsecptr->next;
 695             }
 696           
 697           MM_bs_list_cleanup(section_list,debug);
 698           
 699         }
 700       else
 701         {
 702           puts ("No body information available");
 703           retcode = 1;
 704         }
 705       
 706 
 707 
 708     }
 709   else 
 710     {
 711       printf ("Wrong message number: %lu. The maximum number of messages is %lu.\n",mesgno,stream->nmsgs);
 712       retcode = 1;
 713     }
 714   
 715   return(retcode);
 716   
 717 } /* mm() */
 718 
 719 
 720 /* Internal functions */
 721 
 722 
 723 /* MM get body information
 724  * Accepts: BODY structure pointer
 725  *          prefix string
 726  *          index
 727  *          section list pointer
 728  *          debug switch
 729  */
 730 
 731 /* This function has been taken almost unchanged from mtest.c,
 732  * in the IMAP distribution. There, it is called display_body.
 733  */
 734 
 735 
 736 void get_body_info (BODY *body,char *pfx,long i, MM_bs_list *section_list, long debug)
     /* [<][>][^][v][top][bottom][index][help] */
 737 {
 738 
 739   char tmp[MAILTMPLEN];
 740   char sectno[MAILTMPLEN];
 741   char sectype[MAILTMPLEN];
 742   char *s = tmp;
 743   PARAMETER *par;
 744   PART *part;                  
 745   MM_b_section *newsection;
 746 
 747 
 748   if (body->type == TYPEMULTIPART) 
 749     {
 750       if (debug) printf ("++++multipart\n");
 751       /* if not first time, extend prefix */
 752       if (pfx) sprintf (tmp,"%s%ld.",pfx,++i);
 753       else tmp[0] = '\0';
 754       for (i = 0,part = body->nested.part; part; part = part->next)
 755         get_body_info (&part->body,tmp,i++, section_list, debug);
 756     }
 757   else 
 758     {                        /* non-multipart, output oneline descriptor */
 759       if (debug) printf ("++++nonmultipart\n");
 760       if (!pfx) pfx = "";         /* dummy prefix if top level */
 761 
 762       sprintf (s," %s%ld %s",pfx,++i,body_types[body->type]);
 763 
 764       newsection = (MM_b_section *)malloc(sizeof(MM_b_section));
 765 
 766       newsection->number = (char *)malloc(strlen(sectno)+1);
 767       sprintf (sectno,"%s%ld",pfx,i);
 768       sprintf (newsection->number,"%s",sectno);
 769 
 770       sprintf (sectype, "%s",body_types[body->type]);
 771 
 772       if (body->subtype) 
 773         {
 774           sprintf (s += strlen (s),"/%s",body->subtype);
 775           sprintf (sectype + strlen (sectype),"/%s",body->subtype);
 776         }
 777 
 778       newsection->type = (char *)malloc(strlen(sectype)+1);
 779 
 780       sprintf (newsection->type,"%s",sectype);     
 781 
 782       /* Insert an element at the end of the list */
 783 
 784       MM_bs_list_ins_last (section_list, newsection);
 785 
 786 
 787  
 788       if (body->description) sprintf (s += strlen (s)," (%s)",body->description);
 789 
 790 
 791       if ((par = body->parameter)) 
 792         do
 793           sprintf (s += strlen (s),";%s=%s",par->attribute,par->value);
 794         while ((par = par->next));
 795 
 796       if (body->id) 
 797         sprintf (s += strlen (s),", id = %s",body->id);
 798 
 799       switch (body->type) 
 800         {       /* bytes or lines depending upon body type */
 801         case TYPEMESSAGE:           /* encapsulated message */
 802         case TYPETEXT:              /* plain text */
 803           sprintf (s += strlen (s)," (%lu lines)",body->size.lines);
 804           newsection->size = body->size.bytes;
 805           sprintf (s += strlen (s),"\n   size: %lu",body->contents.text.size);
 806           break;
 807         default:
 808           sprintf (s += strlen (s)," (%lu bytes)",body->size.bytes);
 809           newsection->size = body->size.bytes;
 810           break;
 811         }
 812       if (debug) puts (tmp);                 /* output this line */
 813 
 814    }
 815 
 816   return;
 817 
 818 } /* get_body_info() */
 819 
 820 
 821 /* MM status report
 822  * Accepts: MAIL stream
 823  */
 824 
 825 void status (MAILSTREAM *stream)
     /* [<][>][^][v][top][bottom][index][help] */
 826 {
 827   long i;
 828   char date[MAILTMPLEN];
 829   rfc822_date (date);
 830   puts (date);
 831   if (stream) 
 832     {
 833       if (stream->mailbox)
 834         printf (" %s mailbox: %s, %lu messages, %lu recent\n",
 835                 stream->dtb->name,stream->mailbox,stream->nmsgs,stream->recent);
 836       else puts ("%No mailbox is open on this stream");
 837       if (stream->user_flags[0]) 
 838         {
 839           printf ("Keywords: %s",stream->user_flags[0]);
 840           for (i = 1; i < NUSERFLAGS && stream->user_flags[i]; ++i)
 841             printf (", %s",stream->user_flags[i]);
 842           puts ("");
 843         }
 844     }
 845 } /* status() */
 846 
 847 
 848 
 849 /*Initialize body_section list */
 850 
 851 void MM_bs_list_init (MM_bs_list *section_list)
     /* [<][>][^][v][top][bottom][index][help] */
 852 {
 853 
 854   section_list->size = 0;
 855   section_list->head = NULL;
 856   section_list->tail = NULL;
 857   /* return; */
 858 
 859 } /* MM_bs_list_init() */
 860 
 861 /* Insert an element at the end of the body_section list */
 862 
 863 void MM_bs_list_ins_last (MM_bs_list *section_list, MM_b_section *newsection)
     /* [<][>][^][v][top][bottom][index][help] */
 864 {
 865   
 866   if (section_list->size == 0)
 867     {
 868       section_list->head = newsection;
 869       section_list->tail = newsection;
 870       section_list->size++;
 871     }
 872   else
 873     {
 874       section_list->tail->next = newsection;
 875       section_list->tail = newsection;
 876       section_list->size++;
 877     }
 878 
 879       newsection->next = NULL;
 880 
 881 } /* MM_bs_list_ins_last() */
 882 
 883 
 884 void MM_bs_list_cleanup (MM_bs_list *section_list, long debug)
     /* [<][>][^][v][top][bottom][index][help] */
 885 {
 886   MM_b_section *p;
 887   MM_b_section *q;
 888 
 889   for (p = section_list->head; p != NULL; p = q)
 890     {
 891       q = p->next;
 892       free(p->number);
 893       free(p->type);
 894       free(p->mime_headers);
 895       free(p->contents);
 896       free(p);
 897     }
 898 
 899   
 900 }
 901 
 902 
 903 /*Initialize extracted_mimepart list */
 904 
 905 
 906 
 907 
 908 void MM_xmp_list_init (MM_xmp_list *part_list)
     /* [<][>][^][v][top][bottom][index][help] */
 909 {
 910 
 911   part_list->size = 0;
 912   part_list->head = NULL;
 913   part_list->tail = NULL;
 914   /* return; */
 915 
 916 } /* MM_xmp_list_init() */
 917 
 918 
 919 /* Insert an element at the end of the body_section list */
 920 
 921 void MM_xmp_list_ins_last (MM_xmp_list *part_list, MM_xmp *newpart)
     /* [<][>][^][v][top][bottom][index][help] */
 922 {
 923   
 924   if (part_list->size == 0)
 925     {
 926       part_list->head = newpart;
 927       part_list->tail = newpart;
 928       part_list->size++;
 929     }
 930   else
 931     {
 932       part_list->tail->next = newpart;
 933       part_list->tail = newpart;
 934       part_list->size++;
 935     }
 936 
 937       newpart->next = NULL;
 938 
 939 } /* MM_xmp_list_ins_last() */
 940 
 941 
 942 char *get_header_line (MAILSTREAM *stream, long mesgno, STRINGLIST *cur, char *hdr_title)
     /* [<][>][^][v][top][bottom][index][help] */
 943 {
 944 
 945   unsigned long offset;
 946   size_t tmplength;
 947   char *curtmp;
 948   char *hdr_attr;
 949   long a,b;
 950 
 951 
 952   /* We need to insert the header title into a STRINGLIST structure, as
 953    * this is the type that must be supplied to mail_fetchheader_full.
 954    */
 955 
 956   cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *) 
 957                                      cpystr (hdr_title)));
 958   
 959   /* We don't want to return the header title, but only the contents.
 960    * This offset allows us to strip the header title.
 961    */
 962   
 963   offset = cur->text.size + 2;
 964   
 965   /* Get the header line, if it exists */
 966   
 967   curtmp = mail_fetchheader_full (stream,mesgno,cur,NIL,NIL);
 968 
 969   tmplength = strlen(curtmp);
 970   hdr_attr = (char *)malloc(tmplength);
 971   
 972   /* cur contains the header title string, like "From:", "Subject:" etc.
 973    * tmplength is the length of the corresponding header line extracted
 974    * from the message. If a real line is returned, the header title
 975    * ("From:", "Subject:" etc.) will be contained within, hence
 976    * tmplength >= cur->text.size . This means that if
 977    * (cur->text.size > tmplength), no such header is present in the mail:
 978    * we must return an (almost) empty string.
 979    */
 980   
 981   a = (long)tmplength;
 982   b = (long)cur->text.size;
 983   if (a > b)
 984     {
 985       sprintf (hdr_attr,"%s",curtmp + offset);
 986       /* printf ("%s",hdr_attr); */
 987     }
 988   else
 989     {
 990       sprintf (hdr_attr,"\n\n");
 991     }
 992   
 993   return (hdr_attr);
 994 } /* get_header_line() */
 995 
 996 
 997 /* Subroutine for writing in a file */
 998 
 999 void write_file (char *filename, char *text, size_t text_size)
     /* [<][>][^][v][top][bottom][index][help] */
1000 {
1001 
1002   FILE *fd;
1003   size_t i;
1004 
1005   /* printf ("%s\n",filename); */
1006   
1007   if ((fd = fopen(filename,"w")) != NULL)
1008     {
1009       for (i = 0; i < text_size; i++)
1010         fprintf (fd, "%c",text[i]);
1011       fclose(fd);
1012     }
1013   else
1014     printf ("Error: could not open file %s for writing\n",filename);
1015   
1016 } /* write_file() */
1017 
1018 
1019 void read_file (char *filename)
     /* [<][>][^][v][top][bottom][index][help] */
1020 {
1021 
1022   FILE *fd;
1023   int c;
1024 
1025   if ((fd = fopen (filename,"r")) != NULL)
1026     {
1027       while ((c = getc(fd)) != EOF)
1028         putc (c, stdout);
1029       fclose (fd);
1030     }
1031   else
1032     printf ("Error: could not open file %s for reading\n",filename);
1033 
1034 } /* read_file() */
1035 
1036 
1037 void put_in_file (char *fileprefix, char *extension, char *text, size_t text_size)
     /* [<][>][^][v][top][bottom][index][help] */
1038 {
1039 
1040   char filename[FILENAMELEN];
1041 
1042 
1043   /* Write in a file */
1044   
1045   sprintf (filename,"%s-%s",fileprefix,extension);
1046   /* printf ("%s\n",filename); */
1047   
1048   write_file(filename,text,text_size);
1049   
1050 }/* put_in_file() */
1051 
1052 
1053 /* Stolen from which_keytypes.c and converted to use regex.h instead of libgen.h */
1054 
1055 
1056 int do_regex_test (const char *pattern, char *string)
     /* [<][>][^][v][top][bottom][index][help] */
1057 {
1058 
1059   int match = 0;
1060 
1061   /* These are not used, since REG_NOSUB is specified in regcomp() */
1062   size_t nmatch = 0;
1063   regmatch_t pmatch[1];
1064 
1065   regex_t *re;
1066 
1067   re = (regex_t *)malloc(STR_XL);
1068 
1069   regcomp(re, pattern, REG_NOSUB);
1070   if (regexec(re, string, nmatch, pmatch, 0))
1071     match = 0;
1072   else
1073     match = 1;
1074 
1075   regfree(re);
1076 
1077   return(match);
1078 
1079 } /* do_regex_test() */
1080 
1081 
1082 /* Interfaces to c-client.
1083  * They must be here for the code to be compiled,
1084  * but most can stay empty.
1085  */
1086 
1087 void mm_searched (MAILSTREAM *stream,unsigned long number)
     /* [<][>][^][v][top][bottom][index][help] */
1088 {
1089 }
1090 
1091 
1092 void mm_exists (MAILSTREAM *stream,unsigned long number)
     /* [<][>][^][v][top][bottom][index][help] */
1093 {
1094 }
1095 
1096 
1097 void mm_expunged (MAILSTREAM *stream,unsigned long number)
     /* [<][>][^][v][top][bottom][index][help] */
1098 {
1099 }
1100 
1101 
1102 void mm_flags (MAILSTREAM *stream,unsigned long number)
     /* [<][>][^][v][top][bottom][index][help] */
1103 {
1104 }
1105 
1106 void mm_notify (MAILSTREAM *stream,char *string,long errflg)
     /* [<][>][^][v][top][bottom][index][help] */
1107 {
1108 }
1109 
1110 void mm_list (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
     /* [<][>][^][v][top][bottom][index][help] */
1111 {
1112 }
1113 
1114 void mm_lsub (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
     /* [<][>][^][v][top][bottom][index][help] */
1115 {
1116 }
1117 
1118 void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
     /* [<][>][^][v][top][bottom][index][help] */
1119 {
1120 }
1121 
1122 void mm_log (char *string,long errflg)
     /* [<][>][^][v][top][bottom][index][help] */
1123 {
1124   switch ((short) errflg) {
1125   case NIL:
1126     printf ("[%s]\n",string);
1127     break;
1128   case PARSE:
1129   case WARN:
1130     printf ("%%%s\n",string);
1131     break;
1132   case ERROR:
1133     printf ("?%s\n",string);
1134     break;
1135   }
1136 }
1137 
1138 void mm_dlog (char *string)
     /* [<][>][^][v][top][bottom][index][help] */
1139 {
1140   puts (string);
1141 }
1142 
1143 void mm_login (NETMBX *mb,char *user,char *pwd,long trial)
     /* [<][>][^][v][top][bottom][index][help] */
1144 {
1145 }
1146 
1147 void mm_critical (MAILSTREAM *stream)
     /* [<][>][^][v][top][bottom][index][help] */
1148 {
1149 }
1150 
1151 void mm_nocritical (MAILSTREAM *stream)
     /* [<][>][^][v][top][bottom][index][help] */
1152 {
1153 }
1154 
1155 long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
     /* [<][>][^][v][top][bottom][index][help] */
1156 {
1157 #if UNIXLIKE
1158   kill (getpid (),SIGSTOP);
1159 #else
1160   abort ();
1161 #endif
1162   return NIL;
1163 }
1164 
1165 void mm_fatal (char *string)
     /* [<][>][^][v][top][bottom][index][help] */
1166 {
1167   printf ("?%s\n",string);
1168 }
1169 

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