1 /* 2 * Copyright (c) 1994 Eric P. Allman 3 * Copyright (c) 1994 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 # include "sendmail.h" 10 # include <string.h> 11 12 #ifndef lint 13 static char sccsid[] = "@(#)mime.c 8.22 (Berkeley) 05/15/95"; 14 #endif /* not lint */ 15 16 /* 17 ** MIME support. 18 ** 19 ** I am indebted to John Beck of Hewlett-Packard, who contributed 20 ** his code to me for inclusion. As it turns out, I did not use 21 ** his code since he used a "minimum change" approach that used 22 ** several temp files, and I wanted a "minimum impact" approach 23 ** that would avoid copying. However, looking over his code 24 ** helped me cement my understanding of the problem. 25 ** 26 ** I also looked at, but did not directly use, Nathaniel 27 ** Borenstein's "code.c" module. Again, it functioned as 28 ** a file-to-file translator, which did not fit within my 29 ** design bounds, but it was a useful base for understanding 30 ** the problem. 31 */ 32 33 #if MIME8TO7 34 35 /* character set for hex and base64 encoding */ 36 char Base16Code[] = "0123456789ABCDEF"; 37 char Base64Code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 38 39 /* types of MIME boundaries */ 40 #define MBT_SYNTAX 0 /* syntax error */ 41 #define MBT_NOTSEP 1 /* not a boundary */ 42 #define MBT_INTERMED 2 /* intermediate boundary (no trailing --) */ 43 #define MBT_FINAL 3 /* final boundary (trailing -- included) */ 44 45 static char *MimeBoundaryNames[] = 46 { 47 "SYNTAX", "NOTSEP", "INTERMED", "FINAL" 48 }; 49 /* 50 ** MIME8TO7 -- output 8 bit body in 7 bit format 51 ** 52 ** The header has already been output -- this has to do the 53 ** 8 to 7 bit conversion. It would be easy if we didn't have 54 ** to deal with nested formats (multipart/xxx and message/rfc822). 55 ** 56 ** We won't be called if we don't have to do a conversion, and 57 ** appropriate MIME-Version: and Content-Type: fields have been 58 ** output. Any Content-Transfer-Encoding: field has not been 59 ** output, and we can add it here. 60 ** 61 ** Parameters: 62 ** mci -- mailer connection information. 63 ** header -- the header for this body part. 64 ** e -- envelope. 65 ** boundaries -- the currently pending message boundaries. 66 ** NULL if we are processing the outer portion. 67 ** flags -- to tweak processing. 68 ** 69 ** Returns: 70 ** An indicator of what terminated the message part: 71 ** MBT_FINAL -- the final boundary 72 ** MBT_INTERMED -- an intermediate boundary 73 ** MBT_NOTSEP -- an end of file 74 */ 75 76 struct args 77 { 78 char *field; /* name of field */ 79 char *value; /* value of that field */ 80 }; 81 82 int 83 mime8to7(mci, header, e, boundaries, flags) 84 register MCI *mci; 85 HDR *header; 86 register ENVELOPE *e; 87 char **boundaries; 88 int flags; 89 { 90 register char *p; 91 int linelen; 92 int bt; 93 off_t offset; 94 size_t sectionsize, sectionhighbits; 95 int i; 96 char *type; 97 char *subtype; 98 char *cte; 99 char **pvp; 100 int argc = 0; 101 char *bp; 102 struct args argv[MAXMIMEARGS]; 103 char bbuf[128]; 104 char buf[MAXLINE]; 105 char pvpbuf[MAXLINE]; 106 extern char MimeTokenTab[256]; 107 108 if (tTd(43, 1)) 109 { 110 printf("mime8to7: flags = %x, boundaries =", flags); 111 if (boundaries[0] == NULL) 112 printf(" <none>"); 113 else 114 { 115 for (i = 0; boundaries[i] != NULL; i++) 116 printf(" %s", boundaries[i]); 117 } 118 printf("\n"); 119 } 120 p = hvalue("Content-Transfer-Encoding", header); 121 if (p == NULL || 122 (pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL, 123 MimeTokenTab)) == NULL || 124 pvp[0] == NULL) 125 { 126 cte = NULL; 127 } 128 else 129 { 130 cataddr(pvp, NULL, buf, sizeof buf, '\0'); 131 cte = newstr(buf); 132 } 133 134 type = subtype = NULL; 135 p = hvalue("Content-Type", header); 136 if (p == NULL) 137 { 138 if (bitset(M87F_DIGEST, flags)) 139 p = "message/rfc822"; 140 else 141 p = "text/plain"; 142 } 143 if (p != NULL && 144 (pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL, 145 MimeTokenTab)) != NULL && 146 pvp[0] != NULL) 147 { 148 if (tTd(43, 40)) 149 { 150 for (i = 0; pvp[i] != NULL; i++) 151 printf("pvp[%d] = \"%s\"\n", i, pvp[i]); 152 } 153 type = *pvp++; 154 if (*pvp != NULL && strcmp(*pvp, "/") == 0 && 155 *++pvp != NULL) 156 { 157 subtype = *pvp++; 158 } 159 160 /* break out parameters */ 161 while (*pvp != NULL && argc < MAXMIMEARGS) 162 { 163 /* skip to semicolon separator */ 164 while (*pvp != NULL && strcmp(*pvp, ";") != 0) 165 pvp++; 166 if (*pvp++ == NULL || *pvp == NULL) 167 break; 168 169 /* extract field name */ 170 argv[argc].field = *pvp++; 171 172 /* see if there is a value */ 173 if (*pvp != NULL && strcmp(*pvp, "=") == 0 && 174 (*++pvp == NULL || strcmp(*pvp, ";") != 0)) 175 { 176 argv[argc].value = *pvp; 177 argc++; 178 } 179 } 180 } 181 182 /* check for disaster cases */ 183 if (type == NULL) 184 type = "-none-"; 185 if (subtype == NULL) 186 subtype = "-none-"; 187 188 /* don't propogate some flags more than one level into the message */ 189 flags &= ~M87F_DIGEST; 190 191 /* 192 ** Check for cases that can not be encoded. 193 ** 194 ** For example, you can't encode certain kinds of types 195 ** or already-encoded messages. If we find this case, 196 ** just copy it through. 197 */ 198 199 sprintf(buf, "%s/%s", type, subtype); 200 if (wordinclass(buf, 'n') || (cte != NULL && !wordinclass(cte, 'e'))) 201 flags |= M87F_NO8BIT; 202 203 /* 204 ** Multipart requires special processing. 205 ** 206 ** Do a recursive descent into the message. 207 */ 208 209 if (strcasecmp(type, "multipart") == 0 && !bitset(M87F_NO8BIT, flags)) 210 { 211 int blen; 212 213 if (strcasecmp(subtype, "digest") == 0) 214 flags |= M87F_DIGEST; 215 216 for (i = 0; i < argc; i++) 217 { 218 if (strcasecmp(argv[i].field, "boundary") == 0) 219 break; 220 } 221 if (i >= argc) 222 { 223 syserr("mime8to7: Content-Type: %s missing boundary", p); 224 p = "---"; 225 } 226 else 227 { 228 p = argv[i].value; 229 stripquotes(p); 230 } 231 blen = strlen(p); 232 if (blen > sizeof bbuf - 1) 233 { 234 syserr("mime8to7: multipart boundary \"%s\" too long", 235 p); 236 blen = sizeof bbuf - 1; 237 } 238 strncpy(bbuf, p, blen); 239 bbuf[blen] = '\0'; 240 if (tTd(43, 1)) 241 printf("mime8to7: multipart boundary \"%s\"\n", bbuf); 242 for (i = 0; i < MAXMIMENESTING; i++) 243 if (boundaries[i] == NULL) 244 break; 245 if (i >= MAXMIMENESTING) 246 syserr("mime8to7: multipart nesting boundary too deep"); 247 else 248 { 249 boundaries[i] = bbuf; 250 boundaries[i + 1] = NULL; 251 } 252 mci->mci_flags |= MCIF_INMIME; 253 254 /* skip the early "comment" prologue */ 255 putline("", mci); 256 while (fgets(buf, sizeof buf, e->e_dfp) != NULL) 257 { 258 bt = mimeboundary(buf, boundaries); 259 if (bt != MBT_NOTSEP) 260 break; 261 putxline(buf, mci, PXLF_MAPFROM|PXLF_STRIP8BIT); 262 if (tTd(43, 99)) 263 printf(" ...%s", buf); 264 } 265 if (feof(e->e_dfp)) 266 bt = MBT_FINAL; 267 while (bt != MBT_FINAL) 268 { 269 auto HDR *hdr = NULL; 270 271 sprintf(buf, "--%s", bbuf); 272 putline(buf, mci); 273 if (tTd(43, 35)) 274 printf(" ...%s\n", buf); 275 collect(e->e_dfp, FALSE, FALSE, &hdr, e); 276 if (tTd(43, 101)) 277 putline("+++after collect", mci); 278 putheader(mci, hdr, e); 279 if (tTd(43, 101)) 280 putline("+++after putheader", mci); 281 bt = mime8to7(mci, hdr, e, boundaries, flags); 282 } 283 sprintf(buf, "--%s--", bbuf); 284 putline(buf, mci); 285 if (tTd(43, 35)) 286 printf(" ...%s\n", buf); 287 boundaries[i] = NULL; 288 mci->mci_flags &= ~MCIF_INMIME; 289 290 /* skip the late "comment" epilogue */ 291 while (fgets(buf, sizeof buf, e->e_dfp) != NULL) 292 { 293 bt = mimeboundary(buf, boundaries); 294 if (bt != MBT_NOTSEP) 295 break; 296 putxline(buf, mci, PXLF_MAPFROM|PXLF_STRIP8BIT); 297 if (tTd(43, 99)) 298 printf(" ...%s", buf); 299 } 300 if (feof(e->e_dfp)) 301 bt = MBT_FINAL; 302 if (tTd(43, 3)) 303 printf("\t\t\tmime8to7=>%s (multipart)\n", 304 MimeBoundaryNames[bt]); 305 return bt; 306 } 307 308 /* 309 ** Message/* types -- recurse exactly once. 310 */ 311 312 if (strcasecmp(type, "message") == 0) 313 { 314 if (strcasecmp(subtype, "rfc822") != 0) 315 { 316 flags |= M87F_NO8BIT; 317 } 318 else 319 { 320 register char *q; 321 auto HDR *hdr = NULL; 322 323 putline("", mci); 324 325 mci->mci_flags |= MCIF_INMIME; 326 collect(e->e_dfp, FALSE, FALSE, &hdr, e); 327 if (tTd(43, 101)) 328 putline("+++after collect", mci); 329 putheader(mci, hdr, e); 330 if (tTd(43, 101)) 331 putline("+++after putheader", mci); 332 bt = mime8to7(mci, hdr, e, boundaries, flags); 333 mci->mci_flags &= ~MCIF_INMIME; 334 return bt; 335 } 336 } 337 338 /* 339 ** Non-compound body type 340 ** 341 ** Compute the ratio of seven to eight bit characters; 342 ** use that as a heuristic to decide how to do the 343 ** encoding. 344 */ 345 346 sectionsize = sectionhighbits = 0; 347 if (!bitset(M87F_NO8BIT, flags)) 348 { 349 /* remember where we were */ 350 offset = ftell(e->e_dfp); 351 if (offset == -1) 352 syserr("mime8to7: cannot ftell on df%s", e->e_id); 353 354 /* do a scan of this body type to count character types */ 355 while (fgets(buf, sizeof buf, e->e_dfp) != NULL) 356 { 357 if (mimeboundary(buf, boundaries) != MBT_NOTSEP) 358 break; 359 for (p = buf; *p != '\0'; p++) 360 { 361 /* count bytes with the high bit set */ 362 sectionsize++; 363 if (bitset(0200, *p)) 364 sectionhighbits++; 365 } 366 367 /* 368 ** Heuristic: if 1/4 of the first 4K bytes are 8-bit, 369 ** assume base64. This heuristic avoids double-reading 370 ** large graphics or video files. 371 */ 372 373 if (sectionsize >= 4096 && 374 sectionhighbits > sectionsize / 4) 375 break; 376 } 377 378 /* return to the original offset for processing */ 379 /* XXX use relative seeks to handle >31 bit file sizes? */ 380 if (fseek(e->e_dfp, offset, SEEK_SET) < 0) 381 syserr("mime8to7: cannot fseek on df%s", e->e_id); 382 else 383 clearerr(e->e_dfp); 384 } 385 386 /* 387 ** Heuristically determine encoding method. 388 ** If more than 1/8 of the total characters have the 389 ** eighth bit set, use base64; else use quoted-printable. 390 ** However, only encode binary encoded data as base64, 391 ** since otherwise the NL=>CRLF mapping will be a problem. 392 */ 393 394 if (tTd(43, 8)) 395 { 396 printf("mime8to7: %ld high bit(s) in %ld byte(s), cte=%s\n", 397 sectionhighbits, sectionsize, 398 cte == NULL ? "[none]" : cte); 399 } 400 if (cte != NULL && strcasecmp(cte, "binary") == 0) 401 sectionsize = sectionhighbits; 402 linelen = 0; 403 bp = buf; 404 if (sectionhighbits == 0) 405 { 406 /* no encoding necessary */ 407 if (cte != NULL) 408 { 409 sprintf(buf, "Content-Transfer-Encoding: %s", cte); 410 putline(buf, mci); 411 if (tTd(43, 36)) 412 printf(" ...%s\n", buf); 413 } 414 putline("", mci); 415 mci->mci_flags &= ~MCIF_INHEADER; 416 while (fgets(buf, sizeof buf, e->e_dfp) != NULL) 417 { 418 bt = mimeboundary(buf, boundaries); 419 if (bt != MBT_NOTSEP) 420 break; 421 putline(buf, mci); 422 } 423 if (feof(e->e_dfp)) 424 bt = MBT_FINAL; 425 } 426 else if (sectionsize / 8 < sectionhighbits) 427 { 428 /* use base64 encoding */ 429 int c1, c2; 430 431 putline("Content-Transfer-Encoding: base64", mci); 432 if (tTd(43, 36)) 433 printf(" ...Content-Transfer-Encoding: base64\n"); 434 putline("", mci); 435 mci->mci_flags &= ~MCIF_INHEADER; 436 while ((c1 = mime_getchar_crlf(e->e_dfp, boundaries, &bt)) != EOF) 437 { 438 if (linelen > 71) 439 { 440 *bp = '\0'; 441 putline(buf, mci); 442 linelen = 0; 443 bp = buf; 444 } 445 linelen += 4; 446 *bp++ = Base64Code[(c1 >> 2)]; 447 c1 = (c1 & 0x03) << 4; 448 c2 = mime_getchar_crlf(e->e_dfp, boundaries, &bt); 449 if (c2 == EOF) 450 { 451 *bp++ = Base64Code[c1]; 452 *bp++ = '='; 453 *bp++ = '='; 454 break; 455 } 456 c1 |= (c2 >> 4) & 0x0f; 457 *bp++ = Base64Code[c1]; 458 c1 = (c2 & 0x0f) << 2; 459 c2 = mime_getchar_crlf(e->e_dfp, boundaries, &bt); 460 if (c2 == EOF) 461 { 462 *bp++ = Base64Code[c1]; 463 *bp++ = '='; 464 break; 465 } 466 c1 |= (c2 >> 6) & 0x03; 467 *bp++ = Base64Code[c1]; 468 *bp++ = Base64Code[c2 & 0x3f]; 469 } 470 } 471 else 472 { 473 /* use quoted-printable encoding */ 474 int c1, c2; 475 int fromstate; 476 BITMAP badchars; 477 478 /* set up map of characters that must be mapped */ 479 clrbitmap(badchars); 480 for (c1 = 0x00; c1 < 0x20; c1++) 481 setbitn(c1, badchars); 482 clrbitn('\t', badchars); 483 for (c1 = 0x7f; c1 < 0x100; c1++) 484 setbitn(c1, badchars); 485 setbitn('=', badchars); 486 if (bitnset(M_EBCDIC, mci->mci_mailer->m_flags)) 487 for (p = "!\"#$@[\\]^`{|}~"; *p != '\0'; p++) 488 setbitn(*p, badchars); 489 490 putline("Content-Transfer-Encoding: quoted-printable", mci); 491 if (tTd(43, 36)) 492 printf(" ...Content-Transfer-Encoding: quoted-printable\n"); 493 putline("", mci); 494 mci->mci_flags &= ~MCIF_INHEADER; 495 fromstate = 0; 496 c2 = '\n'; 497 while ((c1 = mime_getchar(e->e_dfp, boundaries, &bt)) != EOF) 498 { 499 if (c1 == '\n') 500 { 501 if (c2 == ' ' || c2 == '\t') 502 { 503 *bp++ = '='; 504 *bp++ = Base16Code[(c2 >> 4) & 0x0f]; 505 *bp++ = Base16Code[c2 & 0x0f]; 506 *bp = '\0'; 507 putline(buf, mci); 508 bp = buf; 509 } 510 *bp = '\0'; 511 putline(buf, mci); 512 linelen = fromstate = 0; 513 bp = buf; 514 c2 = c1; 515 continue; 516 } 517 if (c2 == ' ' && linelen == 4 && fromstate == 4 && 518 bitnset(M_ESCFROM, mci->mci_mailer->m_flags)) 519 { 520 *bp++ = '='; 521 *bp++ = '2'; 522 *bp++ = '0'; 523 linelen += 3; 524 } 525 else if (c2 == ' ' || c2 == '\t') 526 { 527 *bp++ = c2; 528 linelen++; 529 } 530 if (linelen > 72) 531 { 532 *bp++ = '='; 533 *bp = '\0'; 534 putline(buf, mci); 535 linelen = fromstate = 0; 536 bp = buf; 537 c2 = '\n'; 538 } 539 if (bitnset(c1 & 0xff, badchars)) 540 { 541 *bp++ = '='; 542 *bp++ = Base16Code[(c1 >> 4) & 0x0f]; 543 *bp++ = Base16Code[c1 & 0x0f]; 544 linelen += 3; 545 } 546 else if (c1 != ' ' && c1 != '\t') 547 { 548 if (linelen < 4 && c1 == "From"[linelen]) 549 fromstate++; 550 *bp++ = c1; 551 linelen++; 552 } 553 c2 = c1; 554 } 555 556 /* output any saved character */ 557 if (c2 == ' ' || c2 == '\t') 558 { 559 *bp++ = '='; 560 *bp++ = Base16Code[(c2 >> 4) & 0x0f]; 561 *bp++ = Base16Code[c2 & 0x0f]; 562 linelen += 3; 563 } 564 } 565 if (linelen > 0) 566 { 567 *bp = '\0'; 568 putline(buf, mci); 569 } 570 if (tTd(43, 3)) 571 printf("\t\t\tmime8to7=>%s (basic)\n", MimeBoundaryNames[bt]); 572 return bt; 573 } 574 /* 575 ** MIME_GETCHAR -- get a character for MIME processing 576 ** 577 ** Treats boundaries as EOF. 578 ** 579 ** Parameters: 580 ** fp -- the input file. 581 ** boundaries -- the current MIME boundaries. 582 ** btp -- if the return value is EOF, *btp is set to 583 ** the type of the boundary. 584 ** 585 ** Returns: 586 ** The next character in the input stream. 587 */ 588 589 int 590 mime_getchar(fp, boundaries, btp) 591 register FILE *fp; 592 char **boundaries; 593 int *btp; 594 { 595 int c; 596 static u_char *bp = NULL; 597 static int buflen = 0; 598 static bool atbol = TRUE; /* at beginning of line */ 599 static int bt = MBT_SYNTAX; /* boundary type of next EOF */ 600 static u_char buf[128]; /* need not be a full line */ 601 602 if (buflen > 0) 603 { 604 buflen--; 605 return *bp++; 606 } 607 bp = buf; 608 buflen = 0; 609 c = getc(fp); 610 if (c == '\n') 611 { 612 /* might be part of a MIME boundary */ 613 *bp++ = c; 614 atbol = TRUE; 615 c = getc(fp); 616 if (c == '\n') 617 { 618 ungetc(c, fp); 619 return c; 620 } 621 } 622 if (c != EOF) 623 *bp++ = c; 624 else 625 bt = MBT_FINAL; 626 if (atbol && c == '-') 627 { 628 /* check for a message boundary */ 629 c = getc(fp); 630 if (c != '-') 631 { 632 if (c != EOF) 633 *bp++ = c; 634 else 635 bt = MBT_FINAL; 636 buflen = bp - buf - 1; 637 bp = buf; 638 return *bp++; 639 } 640 641 /* got "--", now check for rest of separator */ 642 *bp++ = '-'; 643 while (bp < &buf[sizeof buf - 2] && 644 (c = getc(fp)) != EOF && c != '\n') 645 { 646 *bp++ = c; 647 } 648 *bp = '\0'; 649 bt = mimeboundary(&buf[1], boundaries); 650 switch (bt) 651 { 652 case MBT_FINAL: 653 case MBT_INTERMED: 654 /* we have a message boundary */ 655 buflen = 0; 656 *btp = bt; 657 return EOF; 658 } 659 660 atbol = c == '\n'; 661 if (c != EOF) 662 *bp++ = c; 663 } 664 665 buflen = bp - buf - 1; 666 if (buflen < 0) 667 { 668 *btp = bt; 669 return EOF; 670 } 671 bp = buf; 672 return *bp++; 673 } 674 /* 675 ** MIME_GETCHAR_CRLF -- do mime_getchar, but translate NL => CRLF 676 ** 677 ** Parameters: 678 ** fp -- the input file. 679 ** boundaries -- the current MIME boundaries. 680 ** btp -- if the return value is EOF, *btp is set to 681 ** the type of the boundary. 682 ** 683 ** Returns: 684 ** The next character in the input stream. 685 */ 686 687 int 688 mime_getchar_crlf(fp, boundaries, btp) 689 register FILE *fp; 690 char **boundaries; 691 int *btp; 692 { 693 static bool sendlf = FALSE; 694 int c; 695 696 if (sendlf) 697 { 698 sendlf = FALSE; 699 return '\n'; 700 } 701 c = mime_getchar(fp, boundaries, btp); 702 if (c == '\n') 703 { 704 sendlf = TRUE; 705 return '\r'; 706 } 707 return c; 708 } 709 /* 710 ** MIMEBOUNDARY -- determine if this line is a MIME boundary & its type 711 ** 712 ** Parameters: 713 ** line -- the input line. 714 ** boundaries -- the set of currently pending boundaries. 715 ** 716 ** Returns: 717 ** MBT_NOTSEP -- if this is not a separator line 718 ** MBT_INTERMED -- if this is an intermediate separator 719 ** MBT_FINAL -- if this is a final boundary 720 ** MBT_SYNTAX -- if this is a boundary for the wrong 721 ** enclosure -- i.e., a syntax error. 722 */ 723 724 int 725 mimeboundary(line, boundaries) 726 register char *line; 727 char **boundaries; 728 { 729 int type = MBT_NOTSEP; 730 int i; 731 int savec; 732 733 if (line[0] != '-' || line[1] != '-' || boundaries == NULL) 734 return MBT_NOTSEP; 735 i = strlen(line); 736 if (line[i - 1] == '\n') 737 i--; 738 739 /* strip off trailing whitespace */ 740 while (line[i - 1] == ' ' || line[i - 1] == '\t') 741 i--; 742 savec = line[i]; 743 line[i] = '\0'; 744 745 if (tTd(43, 5)) 746 printf("mimeboundary: line=\"%s\"... ", line); 747 748 /* check for this as an intermediate boundary */ 749 if (isboundary(&line[2], boundaries) >= 0) 750 type = MBT_INTERMED; 751 else if (i > 2 && strncmp(&line[i - 2], "--", 2) == 0) 752 { 753 /* check for a final boundary */ 754 line[i - 2] = '\0'; 755 if (isboundary(&line[2], boundaries) >= 0) 756 type = MBT_FINAL; 757 line[i - 2] = '-'; 758 } 759 760 line[i] = savec; 761 if (tTd(43, 5)) 762 printf("%s\n", MimeBoundaryNames[type]); 763 return type; 764 } 765 /* 766 ** DEFCHARSET -- return default character set for message 767 ** 768 ** The first choice for character set is for the mailer 769 ** corresponding to the envelope sender. If neither that 770 ** nor the global configuration file has a default character 771 ** set defined, return "unknown-8bit" as recommended by 772 ** RFC 1428 section 3. 773 ** 774 ** Parameters: 775 ** e -- the envelope for this message. 776 ** 777 ** Returns: 778 ** The default character set for that mailer. 779 */ 780 781 char * 782 defcharset(e) 783 register ENVELOPE *e; 784 { 785 if (e != NULL && e->e_from.q_mailer != NULL && 786 e->e_from.q_mailer->m_defcharset != NULL) 787 return e->e_from.q_mailer->m_defcharset; 788 if (DefaultCharSet != NULL) 789 return DefaultCharSet; 790 return "unknown-8bit"; 791 } 792 /* 793 ** ISBOUNDARY -- is a given string a currently valid boundary? 794 ** 795 ** Parameters: 796 ** line -- the current input line. 797 ** boundaries -- the list of valid boundaries. 798 ** 799 ** Returns: 800 ** The index number in boundaries if the line is found. 801 ** -1 -- otherwise. 802 ** 803 */ 804 805 int 806 isboundary(line, boundaries) 807 char *line; 808 char **boundaries; 809 { 810 register int i; 811 812 for (i = 0; boundaries[i] != NULL; i++) 813 { 814 if (strcmp(line, boundaries[i]) == 0) 815 return i; 816 } 817 return -1; 818 } 819 820 #endif /* MIME */ 821