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_xmp_list_init
  10. MM_xmp_list_ins_last
  11. get_header_line
  12. write_file
  13. read_file
  14. put_in_file
  15. perform_regex_test
  16. mm_searched
  17. mm_exists
  18. mm_expunged
  19. mm_flags
  20. mm_notify
  21. mm_list
  22. mm_lsub
  23. mm_status
  24. mm_log
  25. mm_dlog
  26. mm_login
  27. mm_critical
  28. mm_nocritical
  29. mm_diskerror
  30. mm_fatal

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

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