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 ( 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 1022 | { 1023 | } 1024 | 1025 | 1026 | void mm_exists (MAILSTREAM *stream,unsigned long number) 1027 | { 1028 | } 1029 | 1030 | 1031 | void mm_expunged (MAILSTREAM *stream,unsigned long number) 1032 | { 1033 | } 1034 | 1035 | 1036 | void mm_flags (MAILSTREAM *stream,unsigned long number) 1037 | { 1038 | } 1039 | 1040 | void mm_notify (MAILSTREAM *stream,char *string,long errflg) 1041 | { 1042 | } 1043 | 1044 | void mm_list (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes) 1045 | { 1046 | } 1047 | 1048 | void mm_lsub (MAILSTREAM *stream,int delimiter,char *mailbox,long attributes) 1049 | { 1050 | } 1051 | 1052 | void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status) 1053 | { 1054 | } 1055 | 1056 | void mm_log (char *string,long errflg) 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) 1073 | { 1074 | puts (string); 1075 | } 1076 | 1077 | void mm_login (NETMBX *mb,char *user,char *pwd,long trial) 1078 | { 1079 | } 1080 | 1081 | void mm_critical (MAILSTREAM *stream) 1082 | { 1083 | } 1084 | 1085 | void mm_nocritical (MAILSTREAM *stream) 1086 | { 1087 | } 1088 | 1089 | long mm_diskerror (MAILSTREAM *stream,long errcode,long serious) 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) 1100 | { 1101 | printf ("?%s\n",string); 1102 | } 1103 |