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.17 $
   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       /* hdr->content_type = get_header_line(stream,mesgno,cur,"Content-Type"); */
 433       /* This gets all the line (with encoding etc.), while we only need the content-type itself */
 434 
 435       hdr->content_type = (char *)malloc(STR_M);
 436       
 437       mail_free_stringlist (&lines);
 438       
 439       if (debug >= 2) printf ("================== DEBUG: After getting headers\n");
 440       
 441       
 442       
 443       if (debug) printf ("Message number: %lu. Total messages: %lu\n", mesgno, stream->nmsgs);
 444       
 445       
 446       /* Get structure of the message: body 
 447          (and envelope, which is unused) */
 448 
 449       if (debug >= 2) 
 450         printf ("================== DEBUG: Calling mail_fetchstructure...\n");
 451       mail_fetchstructure (stream,mesgno,&body);
 452 
 453 
 454       if (debug >= 2) 
 455         printf ("================== DEBUG: Printing body information...\n");
 456 
 457       if (body) 
 458         {
 459           /*printf ("Body encoding: %d (%s)\n", body->encoding, body_encodings[body->encoding]);*/
 460 
 461           /* 
 462            * Switch by supported body types.
 463            * The supported body types are:
 464            * - discrete:
 465            * text/plain
 466            * application/pgp
 467            * application/pgp-signature (inside multipart/signed)
 468            * - composite:
 469            * multipart/mixed
 470            * multipart/alternative
 471            * multipart/signed
 472            */
 473           if (debug >= 2) printf ("================== DEBUG: Calling get_body_info...\n");
 474           get_body_info (body,NIL,(long) 0, section_list, debug);
 475           if (debug >= 2) printf ("================== DEBUG: After get_body_info...\n");
 476                       
 477           secptr = section_list->head;
 478 
 479           if (debug >= 3)
 480             {
 481               printf ("================== DEBUG 3: number: %s\n",secptr->number);
 482               printf ("================== DEBUG 3: type: %s\n",secptr->type);
 483             }
 484 
 485 
 486           sprintf (hdr->content_type,"%s",body_types[body->type]);
 487           if (body->subtype) 
 488               { sprintf (hdr->content_type+strlen(hdr->content_type),"/%s\n\n",body->subtype); }
 489 
 490           switch (body->type)
 491             {
 492 
 493             case TYPETEXT:
 494               mailtext = tmp;
 495               if ((body->subtype) && (!strcmp(body->subtype,"PLAIN")))
 496                 {
 497 
 498                   /* Can this explode with huge messages? */
 499                   mailtext = mail_fetchtext(stream,mesgno);
 500 
 501                   if (debug >= 3)
 502                     {
 503                       printf ("Type text/plain\n");
 504                       printf ("Message contents:\n");
 505                       printf ("%s\n",mailtext); 
 506                     }
 507 
 508                   secptr->supported = 1;
 509 
 510                 }
 511               else
 512                 {
 513                   sprintf (mailtext,"Unsupported content type: %s",
 514                           body_types[body->type]);
 515                   if (body->subtype) sprintf (mailtext+strlen(mailtext),"/%s\n",body->subtype);
 516                   /* printf ("%s",mailtext); */
 517                   secptr->supported = 0;
 518                 }
 519 
 520               /* Write in a file */
 521                   
 522               put_in_file (fileprefix,"1",mailtext,strlen(mailtext));
 523 
 524               break;
 525 
 526             case TYPEAPPLICATION:
 527 
 528               mailtext = tmp;
 529               if ((body->subtype) && (!strcmp(body->subtype,"PGP")))
 530                 {
 531                   mailtext = mail_fetchtext(stream,mesgno);
 532 
 533                   /* printf ("Type application/pgp\n");
 534                      printf ("Message contents:\n");
 535                      printf ("%s\n",mailtext); */
 536 
 537                   secptr->supported = 1;
 538 
 539                 }
 540               else
 541                 {
 542                   sprintf (mailtext,"Unsupported content type: %s",
 543                           body_types[body->type]);
 544                   if (body->subtype) sprintf (mailtext+strlen(mailtext),"/%s\n",body->subtype);
 545                   /* printf ("%s",mailtext); */
 546                   secptr->supported = 0;
 547                 }
 548 
 549               /* Write in a file */
 550               
 551               put_in_file (fileprefix,"1",mailtext,strlen(mailtext));
 552 
 553               break;
 554 
 555             case TYPEMULTIPART:
 556               if (body->subtype)
 557                 {
 558                   if ((!strcmp(body->subtype,"MIXED")) || (!strcmp(body->subtype,"ALTERNATIVE")) || (!strcmp(body->subtype,"SIGNED")))
 559                     {
 560                       /* printf ("Supported content type: %s/%s\n",body_types[body->type],body->subtype); */
 561                       
 562                       
 563                       flags = 0;
 564                       if (debug) printf ("Sections:\n");
 565                       while (secptr != NULL)
 566                         {
 567                           section = secptr->number;
 568                           if (debug) 
 569                             {
 570                               printf("++++++++++++++++++++++++++++++++++++++++++++\n");
 571                               printf ("%s\n",section);
 572                             }
 573                           /*printf ("%s\n",secptr->type);*/
 574                           
 575                           if ((!strcmp(secptr->type,"TEXT/PLAIN")) || (!strcmp(secptr->type,"APPLICATION/PGP-SIGNATURE")))
 576                             {
 577                               secptr->supported = 1;
 578                               result = mail_fetch_mime (stream, mesgno, section, &length, flags);
 579                               
 580                               
 581                               if (debug) 
 582                                 {
 583                                   printf ("Supported content type: %s\n",secptr->type);
 584                                   printf ("Length: %lu . Result: \n",length);
 585                                 }
 586                               
 587                               /* secptr->size: size of the contents of the body part.
 588                                  length: size of the MIME header of the body part. */
 589                               
 590                               secptr->mime_headers = (char *)malloc(length);
 591                               
 592                               strncpy(secptr->mime_headers,result,(size_t)length);
 593                               
 594                               /* printf ("--MIME headers:\n%s\n--End of MIME headers\n",secptr->mime_headers); */
 595                               
 596                               secptr->contents = (char *)malloc(secptr->size);
 597                               
 598                               strncpy(secptr->contents,result + length,(size_t)secptr->size);
 599 
 600                               /* Write in a file */
 601 
 602                               put_in_file (fileprefix,section,secptr->contents,secptr->size);
 603                               
 604                             }
 605                           else
 606                             {
 607                               sprintf (strtmp,"Unsupported content type: %s\n",secptr->type);
 608                               secptr->supported = 0;
 609                               /* printf ("%s",strtmp); */
 610                               /* Write in a file */
 611                               put_in_file (fileprefix,section,strtmp,strlen(strtmp));
 612                             }
 613                           
 614                           
 615                           printf ("\n\n");
 616                           
 617                           
 618                           
 619                           secptr = secptr->next;
 620                         }
 621                     }
 622                   else
 623                     {
 624                       sprintf (strtmp,"Unsupported content type: %s/%s\n",body_types[body->type],body->subtype);
 625                       secptr->supported = 0;
 626                       /* printf ("%s",strtmp); */
 627                       /* Write in a file */
 628                       put_in_file (fileprefix,"1",strtmp,strlen(strtmp));
 629                       /* Problem here - the notice is only written in the first file.
 630                          It is right, for we only should have one file for multipart/unsupported.
 631                          But from get_body_info, section_list is composed of all the parts
 632                          anyway...
 633                          a solution is to reduce here section_list to only one member,
 634                          as follows. */
 635                       secptr->next = NULL;
 636                       section_list->size = 1;
 637 
 638                     }
 639                 }
 640               else
 641                 {
 642 
 643                   /* In current c-client implementation, we _should_ never get here,
 644                      since the subtype "unknown" is added if no subtype is
 645                      specified. */
 646 
 647                   sprintf (strtmp,"Unknown multipart subtype\n");
 648                   secptr->supported = 0;
 649                   /* printf ("%s",strtmp); */
 650                   /* Write in a file */
 651                   put_in_file (fileprefix,"1",strtmp,strlen(strtmp));
 652                   /* Same problem here as above: the notice is
 653                      only written in the first file. We reduce the list to
 654                      a single member. */
 655                   secptr->next = NULL;
 656                   section_list->size = 1;
 657 
 658                 }
 659 
 660               break;
 661 
 662             default:
 663               sprintf (strtmp,"Unsupported content type: %s",body_types[body->type]);
 664               secptr->supported = 0;
 665               if (body->subtype) sprintf (strtmp+strlen(strtmp),"/%s\n",body->subtype);
 666               
 667               /* printf ("%s",strtmp); */
 668 
 669               /* Write in a file */
 670               put_in_file (fileprefix,"1",strtmp,strlen(strtmp));
 671               break;
 672             }
 673 
 674 
 675           /* Copy the relevant information to the structure used
 676              by the API, MM_xmp */
 677 
 678           tmpsecptr = section_list->head;
 679           
 680           while (tmpsecptr != NULL)
 681             {
 682 
 683               newpart = (MM_xmp *)malloc(sizeof(MM_xmp));
 684 
 685               tmpsection = tmpsecptr->number;
 686 
 687               newpart->number = (char *)malloc(strlen(tmpsection) + 1);
 688               sprintf (newpart->number,"%s",tmpsection);
 689               newpart->file = (char *)malloc(strlen(fileprefix) + strlen(tmpsection) + 2);
 690               sprintf (newpart->file,"%s-%s",fileprefix,tmpsection);
 691               newpart->type = (char *)malloc(2+strlen(tmpsecptr->type));
 692               sprintf (newpart->type,"%s",tmpsecptr->type);
 693               /* printf ("%s\n",newpart->number);
 694                  printf ("%s\n",newpart->file);
 695                  if (debug) printf ("Reading file %s...\n",newpart->file);
 696                  read_file(newpart->file); */
 697 
 698               newpart->supported = tmpsecptr->supported;
 699               /* printf("Supported: %hd\n",newpart->supported); */
 700 
 701               MM_xmp_list_ins_last(part_list, newpart);
 702               tmpsecptr = tmpsecptr->next;
 703             }
 704           
 705           MM_bs_list_cleanup(section_list,debug);
 706           
 707         }
 708       else
 709         {
 710           puts ("No body information available");
 711           retcode = 1;
 712         }
 713       
 714 
 715 
 716     }
 717   else 
 718     {
 719       printf ("Wrong message number: %lu. The maximum number of messages is %lu.\n",mesgno,stream->nmsgs);
 720       retcode = 1;
 721     }
 722   
 723   return(retcode);
 724   
 725 } /* mm() */
 726 
 727 
 728 /* Internal functions */
 729 
 730 
 731 /* MM get body information
 732  * Accepts: BODY structure pointer
 733  *          prefix string
 734  *          index
 735  *          section list pointer
 736  *          debug switch
 737  */
 738 
 739 /* This function has been taken almost unchanged from mtest.c,
 740  * in the IMAP distribution. There, it is called display_body.
 741  */
 742 
 743 
 744 void get_body_info (BODY *body,char *pfx,long i, MM_bs_list *section_list, long debug)
     /* [<][>][^][v][top][bottom][index][help] */
 745 {
 746 
 747   char tmp[MAILTMPLEN];
 748   char sectno[MAILTMPLEN];
 749   char sectype[MAILTMPLEN];
 750   char *s = tmp;
 751   PARAMETER *par;
 752   PART *part;                  
 753   MM_b_section *newsection;
 754 
 755 
 756   if (body->type == TYPEMULTIPART) 
 757     {
 758       if (debug) printf ("++++multipart\n");
 759       /* if not first time, extend prefix */
 760       if (pfx) sprintf (tmp,"%s%ld.",pfx,++i);
 761       else tmp[0] = '\0';
 762       for (i = 0,part = body->nested.part; part; part = part->next)
 763         get_body_info (&part->body,tmp,i++, section_list, debug);
 764     }
 765   else 
 766     {                        /* non-multipart, output oneline descriptor */
 767       if (debug) printf ("++++nonmultipart\n");
 768       if (!pfx) pfx = "";         /* dummy prefix if top level */
 769 
 770       sprintf (s," %s%ld %s",pfx,++i,body_types[body->type]);
 771 
 772       newsection = (MM_b_section *)malloc(sizeof(MM_b_section));
 773 
 774       sprintf (sectno,"%s%ld",pfx,i);
 775       newsection->number = (char *)malloc(strlen(sectno)+1);
 776       sprintf (newsection->number,"%s",sectno);
 777 
 778       sprintf (sectype, "%s",body_types[body->type]);
 779 
 780       if (body->subtype) 
 781         {
 782           sprintf (s += strlen (s),"/%s",body->subtype);
 783           sprintf (sectype + strlen (sectype),"/%s",body->subtype);
 784         }
 785 
 786       newsection->type = (char *)malloc(strlen(sectype)+1);
 787 
 788       sprintf (newsection->type,"%s",sectype);     
 789 
 790       /* Insert an element at the end of the list */
 791 
 792       MM_bs_list_ins_last (section_list, newsection);
 793 
 794 
 795  
 796       if (body->description) sprintf (s += strlen (s)," (%s)",body->description);
 797 
 798 
 799       if ((par = body->parameter)) 
 800         do
 801           sprintf (s += strlen (s),";%s=%s",par->attribute,par->value);
 802         while ((par = par->next));
 803 
 804       if (body->id) 
 805         sprintf (s += strlen (s),", id = %s",body->id);
 806 
 807       switch (body->type) 
 808         {       /* bytes or lines depending upon body type */
 809         case TYPEMESSAGE:           /* encapsulated message */
 810         case TYPETEXT:              /* plain text */
 811           sprintf (s += strlen (s)," (%lu lines)",body->size.lines);
 812           newsection->size = body->size.bytes;
 813           sprintf (s += strlen (s),"\n   size: %lu",body->contents.text.size);
 814           break;
 815         default:
 816           sprintf (s += strlen (s)," (%lu bytes)",body->size.bytes);
 817           newsection->size = body->size.bytes;
 818           break;
 819         }
 820       if (debug) puts (tmp);                 /* output this line */
 821 
 822    }
 823 
 824   return;
 825 
 826 } /* get_body_info() */
 827 
 828 
 829 /* MM status report
 830  * Accepts: MAIL stream
 831  */
 832 
 833 void status (MAILSTREAM *stream)
     /* [<][>][^][v][top][bottom][index][help] */
 834 {
 835   long i;
 836   char date[MAILTMPLEN];
 837   rfc822_date (date);
 838   puts (date);
 839   if (stream) 
 840     {
 841       if (stream->mailbox)
 842         printf (" %s mailbox: %s, %lu messages, %lu recent\n",
 843                 stream->dtb->name,stream->mailbox,stream->nmsgs,stream->recent);
 844       else puts ("%No mailbox is open on this stream");
 845       if (stream->user_flags[0]) 
 846         {
 847           printf ("Keywords: %s",stream->user_flags[0]);
 848           for (i = 1; i < NUSERFLAGS && stream->user_flags[i]; ++i)
 849             printf (", %s",stream->user_flags[i]);
 850           puts ("");
 851         }
 852     }
 853 } /* status() */
 854 
 855 
 856 
 857 /*Initialize body_section list */
 858 
 859 void MM_bs_list_init (MM_bs_list *section_list)
     /* [<][>][^][v][top][bottom][index][help] */
 860 {
 861 
 862   section_list->size = 0;
 863   section_list->head = NULL;
 864   section_list->tail = NULL;
 865   /* return; */
 866 
 867 } /* MM_bs_list_init() */
 868 
 869 /* Insert an element at the end of the body_section list */
 870 
 871 void MM_bs_list_ins_last (MM_bs_list *section_list, MM_b_section *newsection)
     /* [<][>][^][v][top][bottom][index][help] */
 872 {
 873   
 874   if (section_list->size == 0)
 875     {
 876       section_list->head = newsection;
 877       section_list->tail = newsection;
 878       section_list->size++;
 879     }
 880   else
 881     {
 882       section_list->tail->next = newsection;
 883       section_list->tail = newsection;
 884       section_list->size++;
 885     }
 886 
 887       newsection->next = NULL;
 888 
 889 } /* MM_bs_list_ins_last() */
 890 
 891 
 892 void MM_bs_list_cleanup (MM_bs_list *section_list, long debug)
     /* [<][>][^][v][top][bottom][index][help] */
 893 {
 894   MM_b_section *p;
 895   MM_b_section *q;
 896 
 897   for (p = section_list->head; p != NULL; p = q)
 898     {
 899       q = p->next;
 900       free(p->number);
 901       free(p->type);
 902       /* free(p->mime_headers); */
 903       /* free(p->contents); */
 904       free(p);
 905     }
 906 
 907   
 908 }
 909 
 910 
 911 /*Initialize extracted_mimepart list */
 912 
 913 
 914 
 915 
 916 void MM_xmp_list_init (MM_xmp_list *part_list)
     /* [<][>][^][v][top][bottom][index][help] */
 917 {
 918 
 919   part_list->size = 0;
 920   part_list->head = NULL;
 921   part_list->tail = NULL;
 922   /* return; */
 923 
 924 } /* MM_xmp_list_init() */
 925 
 926 
 927 /* Insert an element at the end of the body_section list */
 928 
 929 void MM_xmp_list_ins_last (MM_xmp_list *part_list, MM_xmp *newpart)
     /* [<][>][^][v][top][bottom][index][help] */
 930 {
 931   
 932   if (part_list->size == 0)
 933     {
 934       part_list->head = newpart;
 935       part_list->tail = newpart;
 936       part_list->size++;
 937     }
 938   else
 939     {
 940       part_list->tail->next = newpart;
 941       part_list->tail = newpart;
 942       part_list->size++;
 943     }
 944 
 945       newpart->next = NULL;
 946 
 947 } /* MM_xmp_list_ins_last() */
 948 
 949 
 950 char *get_header_line (MAILSTREAM *stream, long mesgno, STRINGLIST *cur, char *hdr_title)
     /* [<][>][^][v][top][bottom][index][help] */
 951 {
 952 
 953   unsigned long offset;
 954   size_t tmplength;
 955   char *curtmp;
 956   char *hdr_attr;
 957   long a,b;
 958 
 959 
 960   /* We need to insert the header title into a STRINGLIST structure, as
 961    * this is the type that must be supplied to mail_fetchheader_full.
 962    */
 963 
 964   cur->text.size = strlen ((char *) (cur->text.data = (unsigned char *) 
 965                                      cpystr (hdr_title)));
 966   
 967   /* We don't want to return the header title, but only the contents.
 968    * This offset allows us to strip the header title.
 969    */
 970   
 971   offset = cur->text.size + 2;
 972   
 973   /* Get the header line, if it exists */
 974   
 975   curtmp = mail_fetchheader_full (stream,mesgno,cur,NIL,NIL);
 976 
 977   tmplength = strlen(curtmp);
 978   hdr_attr = (char *)malloc(tmplength + 2);
 979   
 980   /* cur contains the header title string, like "From:", "Subject:" etc.
 981    * tmplength is the length of the corresponding header line extracted
 982    * from the message. If a real line is returned, the header title
 983    * ("From:", "Subject:" etc.) will be contained within, hence
 984    * tmplength >= cur->text.size . This means that if
 985    * (cur->text.size > tmplength), no such header is present in the mail:
 986    * we must return an (almost) empty string.
 987    */
 988   
 989   a = (long)tmplength;
 990   b = (long)cur->text.size;
 991   if (a > b)
 992     {
 993       sprintf (hdr_attr,"%s",curtmp + offset);
 994       /* printf ("%s",hdr_attr); */
 995     }
 996   else
 997     {
 998       sprintf (hdr_attr,"\n\n");
 999     }
1000   
1001   return (hdr_attr);
1002 } /* get_header_line() */
1003 
1004 
1005 /* Subroutine for writing in a file */
1006 
1007 void write_file (char *filename, char *text, size_t text_size)
     /* [<][>][^][v][top][bottom][index][help] */
1008 {
1009 
1010   FILE *fd;
1011   size_t i;
1012 
1013   /* printf ("%s\n",filename); */
1014   
1015   if ((fd = fopen(filename,"w")) != NULL)
1016     {
1017       for (i = 0; i < text_size; i++)
1018         fprintf (fd, "%c",text[i]);
1019       fclose(fd);
1020     }
1021   else
1022     printf ("Error: could not open file %s for writing\n",filename);
1023   
1024 } /* write_file() */
1025 
1026 
1027 void read_file (char *filename)
     /* [<][>][^][v][top][bottom][index][help] */
1028 {
1029 
1030   FILE *fd;
1031   int c;
1032 
1033   if ((fd = fopen (filename,"r")) != NULL)
1034     {
1035       while ((c = getc(fd)) != EOF)
1036         putc (c, stdout);
1037       fclose (fd);
1038     }
1039   else
1040     printf ("Error: could not open file %s for reading\n",filename);
1041 
1042 } /* read_file() */
1043 
1044 
1045 void put_in_file (char *fileprefix, char *extension, char *text, size_t text_size)
     /* [<][>][^][v][top][bottom][index][help] */
1046 {
1047 
1048   char filename[FILENAMELEN];
1049 
1050 
1051   /* Write in a file */
1052   
1053   sprintf (filename,"%s-%s",fileprefix,extension);
1054   /* printf ("%s\n",filename); */
1055   
1056   write_file(filename,text,text_size);
1057   
1058 }/* put_in_file() */
1059 
1060 
1061 /* Stolen from which_keytypes.c and converted to use regex.h instead of libgen.h */
1062 
1063 
1064 int do_regex_test (const char *pattern, char *string)
     /* [<][>][^][v][top][bottom][index][help] */
1065 {
1066 
1067   int match = 0;
1068 
1069   /* These are not used, since REG_NOSUB is specified in regcomp() */
1070   size_t nmatch = 0;
1071   regmatch_t pmatch[1];
1072 
1073   regex_t *re;
1074 
1075   re = (regex_t *)malloc(STR_XL);
1076 
1077   regcomp(re, pattern, REG_NOSUB);
1078   if (regexec(re, string, nmatch, pmatch, 0))
1079     match = 0;
1080   else
1081     match = 1;
1082 
1083   regfree(re);
1084 
1085   /* I thought regfree() would do this job... 
1086    * Apparently, it doesn't. 
1087    */
1088   free(re);
1089 
1090   return(match);
1091 
1092 } /* do_regex_test() */
1093 
1094 
1095 /* Interfaces to c-client.
1096  * They must be here for the code to be compiled,
1097  * but most can stay empty.
1098  */
1099 
1100 void mm_searched (MAILSTREAM *stream,unsigned long number)
     /* [<][>][^][v][top][bottom][index][help] */
1101 {
1102 }
1103 
1104 
1105 void mm_exists (MAILSTREAM *stream,unsigned long number)
     /* [<][>][^][v][top][bottom][index][help] */
1106 {
1107 }
1108 
1109 
1110 void mm_expunged (MAILSTREAM *stream,unsigned long number)
     /* [<][>][^][v][top][bottom][index][help] */
1111 {
1112 }
1113 
1114 
1115 void mm_flags (MAILSTREAM *stream,unsigned long number)
     /* [<][>][^][v][top][bottom][index][help] */
1116 {
1117 }
1118 
1119 void mm_notify (MAILSTREAM *stream,char *string,long errflg)
     /* [<][>][^][v][top][bottom][index][help] */
1120 {
1121 }
1122 
1123 void mm_list (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
     /* [<][>][^][v][top][bottom][index][help] */
1124 {
1125 }
1126 
1127 void mm_lsub (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes)
     /* [<][>][^][v][top][bottom][index][help] */
1128 {
1129 }
1130 
1131 void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status)
     /* [<][>][^][v][top][bottom][index][help] */
1132 {
1133 }
1134 
1135 void mm_log (char *string,long errflg)
     /* [<][>][^][v][top][bottom][index][help] */
1136 {
1137   switch ((short) errflg) {
1138   case NIL:
1139     printf ("[%s]\n",string);
1140     break;
1141   case PARSE:
1142   case WARN:
1143     printf ("%%%s\n",string);
1144     break;
1145   case ERROR:
1146     printf ("?%s\n",string);
1147     break;
1148   }
1149 }
1150 
1151 void mm_dlog (char *string)
     /* [<][>][^][v][top][bottom][index][help] */
1152 {
1153   puts (string);
1154 }
1155 
1156 void mm_login (NETMBX *mb,char *user,char *pwd,long trial)
     /* [<][>][^][v][top][bottom][index][help] */
1157 {
1158 }
1159 
1160 void mm_critical (MAILSTREAM *stream)
     /* [<][>][^][v][top][bottom][index][help] */
1161 {
1162 }
1163 
1164 void mm_nocritical (MAILSTREAM *stream)
     /* [<][>][^][v][top][bottom][index][help] */
1165 {
1166 }
1167 
1168 long mm_diskerror (MAILSTREAM *stream,long errcode,long serious)
     /* [<][>][^][v][top][bottom][index][help] */
1169 {
1170 #if UNIXLIKE
1171   kill (getpid (),SIGSTOP);
1172 #else
1173   abort ();
1174 #endif
1175   return NIL;
1176 }
1177 
1178 void mm_fatal (char *string)
     /* [<][>][^][v][top][bottom][index][help] */
1179 {
1180   printf ("?%s\n",string);
1181 }
1182 

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