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.23 (Berkeley) 05/22/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 *bp = '\0'; 471 putline(buf, mci); 472 } 473 else 474 { 475 /* use quoted-printable encoding */ 476 int c1, c2; 477 int fromstate; 478 BITMAP badchars; 479 480 /* set up map of characters that must be mapped */ 481 clrbitmap(badchars); 482 for (c1 = 0x00; c1 < 0x20; c1++) 483 setbitn(c1, badchars); 484 clrbitn('\t', badchars); 485 for (c1 = 0x7f; c1 < 0x100; c1++) 486 setbitn(c1, badchars); 487 setbitn('=', badchars); 488 if (bitnset(M_EBCDIC, mci->mci_mailer->m_flags)) 489 for (p = "!\"#$@[\\]^`{|}~"; *p != '\0'; p++) 490 setbitn(*p, badchars); 491 492 putline("Content-Transfer-Encoding: quoted-printable", mci); 493 if (tTd(43, 36)) 494 printf(" ...Content-Transfer-Encoding: quoted-printable\n"); 495 putline("", mci); 496 mci->mci_flags &= ~MCIF_INHEADER; 497 fromstate = 0; 498 c2 = '\n'; 499 while ((c1 = mime_getchar(e->e_dfp, boundaries, &bt)) != EOF) 500 { 501 if (c1 == '\n') 502 { 503 if (c2 == ' ' || c2 == '\t') 504 { 505 *bp++ = '='; 506 *bp++ = Base16Code[(c2 >> 4) & 0x0f]; 507 *bp++ = Base16Code[c2 & 0x0f]; 508 } 509 *bp = '\0'; 510 putline(buf, mci); 511 linelen = fromstate = 0; 512 bp = buf; 513 c2 = c1; 514 continue; 515 } 516 if (c2 == ' ' && linelen == 4 && fromstate == 4 && 517 bitnset(M_ESCFROM, mci->mci_mailer->m_flags)) 518 { 519 *bp++ = '='; 520 *bp++ = '2'; 521 *bp++ = '0'; 522 linelen += 3; 523 } 524 else if (c2 == ' ' || c2 == '\t') 525 { 526 *bp++ = c2; 527 linelen++; 528 } 529 if (linelen > 72) 530 { 531 *bp++ = '='; 532 *bp = '\0'; 533 putline(buf, mci); 534 linelen = fromstate = 0; 535 bp = buf; 536 c2 = '\n'; 537 } 538 if (bitnset(c1 & 0xff, badchars)) 539 { 540 *bp++ = '='; 541 *bp++ = Base16Code[(c1 >> 4) & 0x0f]; 542 *bp++ = Base16Code[c1 & 0x0f]; 543 linelen += 3; 544 } 545 else if (c1 != ' ' && c1 != '\t') 546 { 547 if (linelen < 4 && c1 == "From"[linelen]) 548 fromstate++; 549 *bp++ = c1; 550 linelen++; 551 } 552 c2 = c1; 553 } 554 555 /* output any saved character */ 556 if (c2 == ' ' || c2 == '\t') 557 { 558 *bp++ = '='; 559 *bp++ = Base16Code[(c2 >> 4) & 0x0f]; 560 *bp++ = Base16Code[c2 & 0x0f]; 561 linelen += 3; 562 } 563 564 if (linelen > 0 || boundaries[0] != NULL) 565 { 566 *bp = '\0'; 567 putline(buf, mci); 568 } 569 570 } 571 if (tTd(43, 3)) 572 printf("\t\t\tmime8to7=>%s (basic)\n", MimeBoundaryNames[bt]); 573 return bt; 574 } 575 /* 576 ** MIME_GETCHAR -- get a character for MIME processing 577 ** 578 ** Treats boundaries as EOF. 579 ** 580 ** Parameters: 581 ** fp -- the input file. 582 ** boundaries -- the current MIME boundaries. 583 ** btp -- if the return value is EOF, *btp is set to 584 ** the type of the boundary. 585 ** 586 ** Returns: 587 ** The next character in the input stream. 588 */ 589 590 int 591 mime_getchar(fp, boundaries, btp) 592 register FILE *fp; 593 char **boundaries; 594 int *btp; 595 { 596 int c; 597 static u_char *bp = NULL; 598 static int buflen = 0; 599 static bool atbol = TRUE; /* at beginning of line */ 600 static int bt = MBT_SYNTAX; /* boundary type of next EOF */ 601 static u_char buf[128]; /* need not be a full line */ 602 603 if (buflen > 0) 604 { 605 buflen--; 606 return *bp++; 607 } 608 bp = buf; 609 buflen = 0; 610 c = getc(fp); 611 if (c == '\n') 612 { 613 /* might be part of a MIME boundary */ 614 *bp++ = c; 615 atbol = TRUE; 616 c = getc(fp); 617 if (c == '\n') 618 { 619 ungetc(c, fp); 620 return c; 621 } 622 } 623 if (c != EOF) 624 *bp++ = c; 625 else 626 bt = MBT_FINAL; 627 if (atbol && c == '-') 628 { 629 /* check for a message boundary */ 630 c = getc(fp); 631 if (c != '-') 632 { 633 if (c != EOF) 634 *bp++ = c; 635 else 636 bt = MBT_FINAL; 637 buflen = bp - buf - 1; 638 bp = buf; 639 return *bp++; 640 } 641 642 /* got "--", now check for rest of separator */ 643 *bp++ = '-'; 644 while (bp < &buf[sizeof buf - 2] && 645 (c = getc(fp)) != EOF && c != '\n') 646 { 647 *bp++ = c; 648 } 649 *bp = '\0'; 650 bt = mimeboundary(&buf[1], boundaries); 651 switch (bt) 652 { 653 case MBT_FINAL: 654 case MBT_INTERMED: 655 /* we have a message boundary */ 656 buflen = 0; 657 *btp = bt; 658 return EOF; 659 } 660 661 atbol = c == '\n'; 662 if (c != EOF) 663 *bp++ = c; 664 } 665 666 buflen = bp - buf - 1; 667 if (buflen < 0) 668 { 669 *btp = bt; 670 return EOF; 671 } 672 bp = buf; 673 return *bp++; 674 } 675 /* 676 ** MIME_GETCHAR_CRLF -- do mime_getchar, but translate NL => CRLF 677 ** 678 ** Parameters: 679 ** fp -- the input file. 680 ** boundaries -- the current MIME boundaries. 681 ** btp -- if the return value is EOF, *btp is set to 682 ** the type of the boundary. 683 ** 684 ** Returns: 685 ** The next character in the input stream. 686 */ 687 688 int 689 mime_getchar_crlf(fp, boundaries, btp) 690 register FILE *fp; 691 char **boundaries; 692 int *btp; 693 { 694 static bool sendlf = FALSE; 695 int c; 696 697 if (sendlf) 698 { 699 sendlf = FALSE; 700 return '\n'; 701 } 702 c = mime_getchar(fp, boundaries, btp); 703 if (c == '\n') 704 { 705 sendlf = TRUE; 706 return '\r'; 707 } 708 return c; 709 } 710 /* 711 ** MIMEBOUNDARY -- determine if this line is a MIME boundary & its type 712 ** 713 ** Parameters: 714 ** line -- the input line. 715 ** boundaries -- the set of currently pending boundaries. 716 ** 717 ** Returns: 718 ** MBT_NOTSEP -- if this is not a separator line 719 ** MBT_INTERMED -- if this is an intermediate separator 720 ** MBT_FINAL -- if this is a final boundary 721 ** MBT_SYNTAX -- if this is a boundary for the wrong 722 ** enclosure -- i.e., a syntax error. 723 */ 724 725 int 726 mimeboundary(line, boundaries) 727 register char *line; 728 char **boundaries; 729 { 730 int type = MBT_NOTSEP; 731 int i; 732 int savec; 733 734 if (line[0] != '-' || line[1] != '-' || boundaries == NULL) 735 return MBT_NOTSEP; 736 i = strlen(line); 737 if (line[i - 1] == '\n') 738 i--; 739 740 /* strip off trailing whitespace */ 741 while (line[i - 1] == ' ' || line[i - 1] == '\t') 742 i--; 743 savec = line[i]; 744 line[i] = '\0'; 745 746 if (tTd(43, 5)) 747 printf("mimeboundary: line=\"%s\"... ", line); 748 749 /* check for this as an intermediate boundary */ 750 if (isboundary(&line[2], boundaries) >= 0) 751 type = MBT_INTERMED; 752 else if (i > 2 && strncmp(&line[i - 2], "--", 2) == 0) 753 { 754 /* check for a final boundary */ 755 line[i - 2] = '\0'; 756 if (isboundary(&line[2], boundaries) >= 0) 757 type = MBT_FINAL; 758 line[i - 2] = '-'; 759 } 760 761 line[i] = savec; 762 if (tTd(43, 5)) 763 printf("%s\n", MimeBoundaryNames[type]); 764 return type; 765 } 766 /* 767 ** DEFCHARSET -- return default character set for message 768 ** 769 ** The first choice for character set is for the mailer 770 ** corresponding to the envelope sender. If neither that 771 ** nor the global configuration file has a default character 772 ** set defined, return "unknown-8bit" as recommended by 773 ** RFC 1428 section 3. 774 ** 775 ** Parameters: 776 ** e -- the envelope for this message. 777 ** 778 ** Returns: 779 ** The default character set for that mailer. 780 */ 781 782 char * 783 defcharset(e) 784 register ENVELOPE *e; 785 { 786 if (e != NULL && e->e_from.q_mailer != NULL && 787 e->e_from.q_mailer->m_defcharset != NULL) 788 return e->e_from.q_mailer->m_defcharset; 789 if (DefaultCharSet != NULL) 790 return DefaultCharSet; 791 return "unknown-8bit"; 792 } 793 /* 794 ** ISBOUNDARY -- is a given string a currently valid boundary? 795 ** 796 ** Parameters: 797 ** line -- the current input line. 798 ** boundaries -- the list of valid boundaries. 799 ** 800 ** Returns: 801 ** The index number in boundaries if the line is found. 802 ** -1 -- otherwise. 803 ** 804 */ 805 806 int 807 isboundary(line, boundaries) 808 char *line; 809 char **boundaries; 810 { 811 register int i; 812 813 for (i = 0; boundaries[i] != NULL; i++) 814 { 815 if (strcmp(line, boundaries[i]) == 0) 816 return i; 817 } 818 return -1; 819 } 820 821 #endif /* MIME */ 822