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.26 (Berkeley) 06/18/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
mime8to7(mci,header,e,boundaries,flags)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 u_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 ** Class 'm' is predefined to have "rfc822" only.
312 */
313
314 if (strcasecmp(type, "message") == 0)
315 {
316 if (!wordinclass(subtype, 'm'))
317 {
318 flags |= M87F_NO8BIT;
319 }
320 else
321 {
322 auto HDR *hdr = NULL;
323
324 putline("", mci);
325
326 mci->mci_flags |= MCIF_INMIME;
327 collect(e->e_dfp, FALSE, FALSE, &hdr, e);
328 if (tTd(43, 101))
329 putline("+++after collect", mci);
330 putheader(mci, hdr, e);
331 if (tTd(43, 101))
332 putline("+++after putheader", mci);
333 if (hvalue("MIME-Version", hdr) == NULL)
334 putline("MIME-Version: 1.0", mci);
335 bt = mime8to7(mci, hdr, e, boundaries, flags);
336 mci->mci_flags &= ~MCIF_INMIME;
337 return bt;
338 }
339 }
340
341 /*
342 ** Non-compound body type
343 **
344 ** Compute the ratio of seven to eight bit characters;
345 ** use that as a heuristic to decide how to do the
346 ** encoding.
347 */
348
349 sectionsize = sectionhighbits = 0;
350 if (!bitset(M87F_NO8BIT, flags))
351 {
352 /* remember where we were */
353 offset = ftell(e->e_dfp);
354 if (offset == -1)
355 syserr("mime8to7: cannot ftell on df%s", e->e_id);
356
357 /* do a scan of this body type to count character types */
358 while (fgets(buf, sizeof buf, e->e_dfp) != NULL)
359 {
360 if (mimeboundary(buf, boundaries) != MBT_NOTSEP)
361 break;
362 for (p = buf; *p != '\0'; p++)
363 {
364 /* count bytes with the high bit set */
365 sectionsize++;
366 if (bitset(0200, *p))
367 sectionhighbits++;
368 }
369
370 /*
371 ** Heuristic: if 1/4 of the first 4K bytes are 8-bit,
372 ** assume base64. This heuristic avoids double-reading
373 ** large graphics or video files.
374 */
375
376 if (sectionsize >= 4096 &&
377 sectionhighbits > sectionsize / 4)
378 break;
379 }
380
381 /* return to the original offset for processing */
382 /* XXX use relative seeks to handle >31 bit file sizes? */
383 if (fseek(e->e_dfp, offset, SEEK_SET) < 0)
384 syserr("mime8to7: cannot fseek on df%s", e->e_id);
385 else
386 clearerr(e->e_dfp);
387 }
388
389 /*
390 ** Heuristically determine encoding method.
391 ** If more than 1/8 of the total characters have the
392 ** eighth bit set, use base64; else use quoted-printable.
393 ** However, only encode binary encoded data as base64,
394 ** since otherwise the NL=>CRLF mapping will be a problem.
395 */
396
397 if (tTd(43, 8))
398 {
399 printf("mime8to7: %ld high bit(s) in %ld byte(s), cte=%s\n",
400 sectionhighbits, sectionsize,
401 cte == NULL ? "[none]" : cte);
402 }
403 if (cte != NULL && strcasecmp(cte, "binary") == 0)
404 sectionsize = sectionhighbits;
405 linelen = 0;
406 bp = buf;
407 if (sectionhighbits == 0)
408 {
409 /* no encoding necessary */
410 if (cte != NULL)
411 {
412 sprintf(buf, "Content-Transfer-Encoding: %s", cte);
413 putline(buf, mci);
414 if (tTd(43, 36))
415 printf(" ...%s\n", buf);
416 }
417 putline("", mci);
418 mci->mci_flags &= ~MCIF_INHEADER;
419 while (fgets(buf, sizeof buf, e->e_dfp) != NULL)
420 {
421 bt = mimeboundary(buf, boundaries);
422 if (bt != MBT_NOTSEP)
423 break;
424 putline(buf, mci);
425 }
426 if (feof(e->e_dfp))
427 bt = MBT_FINAL;
428 }
429 else if (sectionsize / 8 < sectionhighbits)
430 {
431 /* use base64 encoding */
432 int c1, c2;
433
434 putline("Content-Transfer-Encoding: base64", mci);
435 if (tTd(43, 36))
436 printf(" ...Content-Transfer-Encoding: base64\n");
437 putline("", mci);
438 mci->mci_flags &= ~MCIF_INHEADER;
439 while ((c1 = mime_getchar_crlf(e->e_dfp, boundaries, &bt)) != EOF)
440 {
441 if (linelen > 71)
442 {
443 *bp = '\0';
444 putline(buf, mci);
445 linelen = 0;
446 bp = buf;
447 }
448 linelen += 4;
449 *bp++ = Base64Code[(c1 >> 2)];
450 c1 = (c1 & 0x03) << 4;
451 c2 = mime_getchar_crlf(e->e_dfp, boundaries, &bt);
452 if (c2 == EOF)
453 {
454 *bp++ = Base64Code[c1];
455 *bp++ = '=';
456 *bp++ = '=';
457 break;
458 }
459 c1 |= (c2 >> 4) & 0x0f;
460 *bp++ = Base64Code[c1];
461 c1 = (c2 & 0x0f) << 2;
462 c2 = mime_getchar_crlf(e->e_dfp, boundaries, &bt);
463 if (c2 == EOF)
464 {
465 *bp++ = Base64Code[c1];
466 *bp++ = '=';
467 break;
468 }
469 c1 |= (c2 >> 6) & 0x03;
470 *bp++ = Base64Code[c1];
471 *bp++ = Base64Code[c2 & 0x3f];
472 }
473 *bp = '\0';
474 putline(buf, mci);
475 }
476 else
477 {
478 /* use quoted-printable encoding */
479 int c1, c2;
480 int fromstate;
481 BITMAP badchars;
482
483 /* set up map of characters that must be mapped */
484 clrbitmap(badchars);
485 for (c1 = 0x00; c1 < 0x20; c1++)
486 setbitn(c1, badchars);
487 clrbitn('\t', badchars);
488 for (c1 = 0x7f; c1 < 0x100; c1++)
489 setbitn(c1, badchars);
490 setbitn('=', badchars);
491 if (bitnset(M_EBCDIC, mci->mci_mailer->m_flags))
492 for (p = "!\"#$@[\\]^`{|}~"; *p != '\0'; p++)
493 setbitn(*p, badchars);
494
495 putline("Content-Transfer-Encoding: quoted-printable", mci);
496 if (tTd(43, 36))
497 printf(" ...Content-Transfer-Encoding: quoted-printable\n");
498 putline("", mci);
499 mci->mci_flags &= ~MCIF_INHEADER;
500 fromstate = 0;
501 c2 = '\n';
502 while ((c1 = mime_getchar(e->e_dfp, boundaries, &bt)) != EOF)
503 {
504 if (c1 == '\n')
505 {
506 if (c2 == ' ' || c2 == '\t')
507 {
508 *bp++ = '=';
509 *bp++ = Base16Code[(c2 >> 4) & 0x0f];
510 *bp++ = Base16Code[c2 & 0x0f];
511 }
512 *bp = '\0';
513 putline(buf, mci);
514 linelen = fromstate = 0;
515 bp = buf;
516 c2 = c1;
517 continue;
518 }
519 if (c2 == ' ' && linelen == 4 && fromstate == 4 &&
520 bitnset(M_ESCFROM, mci->mci_mailer->m_flags))
521 {
522 *bp++ = '=';
523 *bp++ = '2';
524 *bp++ = '0';
525 linelen += 3;
526 }
527 else if (c2 == ' ' || c2 == '\t')
528 {
529 *bp++ = c2;
530 linelen++;
531 }
532 if (linelen > 72)
533 {
534 *bp++ = '=';
535 *bp = '\0';
536 putline(buf, mci);
537 linelen = fromstate = 0;
538 bp = buf;
539 c2 = '\n';
540 }
541 if (bitnset(c1 & 0xff, badchars))
542 {
543 *bp++ = '=';
544 *bp++ = Base16Code[(c1 >> 4) & 0x0f];
545 *bp++ = Base16Code[c1 & 0x0f];
546 linelen += 3;
547 }
548 else if (c1 != ' ' && c1 != '\t')
549 {
550 if (linelen < 4 && c1 == "From"[linelen])
551 fromstate++;
552 *bp++ = c1;
553 linelen++;
554 }
555 c2 = c1;
556 }
557
558 /* output any saved character */
559 if (c2 == ' ' || c2 == '\t')
560 {
561 *bp++ = '=';
562 *bp++ = Base16Code[(c2 >> 4) & 0x0f];
563 *bp++ = Base16Code[c2 & 0x0f];
564 linelen += 3;
565 }
566
567 if (linelen > 0 || boundaries[0] != NULL)
568 {
569 *bp = '\0';
570 putline(buf, mci);
571 }
572
573 }
574 if (tTd(43, 3))
575 printf("\t\t\tmime8to7=>%s (basic)\n", MimeBoundaryNames[bt]);
576 return bt;
577 }
578 /*
579 ** MIME_GETCHAR -- get a character for MIME processing
580 **
581 ** Treats boundaries as EOF.
582 **
583 ** Parameters:
584 ** fp -- the input file.
585 ** boundaries -- the current MIME boundaries.
586 ** btp -- if the return value is EOF, *btp is set to
587 ** the type of the boundary.
588 **
589 ** Returns:
590 ** The next character in the input stream.
591 */
592
593 int
mime_getchar(fp,boundaries,btp)594 mime_getchar(fp, boundaries, btp)
595 register FILE *fp;
596 char **boundaries;
597 int *btp;
598 {
599 int c;
600 static u_char *bp = NULL;
601 static int buflen = 0;
602 static bool atbol = TRUE; /* at beginning of line */
603 static int bt = MBT_SYNTAX; /* boundary type of next EOF */
604 static u_char buf[128]; /* need not be a full line */
605
606 if (buflen > 0)
607 {
608 buflen--;
609 return *bp++;
610 }
611 bp = buf;
612 buflen = 0;
613 c = getc(fp);
614 if (c == '\n')
615 {
616 /* might be part of a MIME boundary */
617 *bp++ = c;
618 atbol = TRUE;
619 c = getc(fp);
620 if (c == '\n')
621 {
622 ungetc(c, fp);
623 return c;
624 }
625 }
626 if (c != EOF)
627 *bp++ = c;
628 else
629 bt = MBT_FINAL;
630 if (atbol && c == '-')
631 {
632 /* check for a message boundary */
633 c = getc(fp);
634 if (c != '-')
635 {
636 if (c != EOF)
637 *bp++ = c;
638 else
639 bt = MBT_FINAL;
640 buflen = bp - buf - 1;
641 bp = buf;
642 return *bp++;
643 }
644
645 /* got "--", now check for rest of separator */
646 *bp++ = '-';
647 while (bp < &buf[sizeof buf - 2] &&
648 (c = getc(fp)) != EOF && c != '\n')
649 {
650 *bp++ = c;
651 }
652 *bp = '\0';
653 bt = mimeboundary(&buf[1], boundaries);
654 switch (bt)
655 {
656 case MBT_FINAL:
657 case MBT_INTERMED:
658 /* we have a message boundary */
659 buflen = 0;
660 *btp = bt;
661 return EOF;
662 }
663
664 atbol = c == '\n';
665 if (c != EOF)
666 *bp++ = c;
667 }
668
669 buflen = bp - buf - 1;
670 if (buflen < 0)
671 {
672 *btp = bt;
673 return EOF;
674 }
675 bp = buf;
676 return *bp++;
677 }
678 /*
679 ** MIME_GETCHAR_CRLF -- do mime_getchar, but translate NL => CRLF
680 **
681 ** Parameters:
682 ** fp -- the input file.
683 ** boundaries -- the current MIME boundaries.
684 ** btp -- if the return value is EOF, *btp is set to
685 ** the type of the boundary.
686 **
687 ** Returns:
688 ** The next character in the input stream.
689 */
690
691 int
mime_getchar_crlf(fp,boundaries,btp)692 mime_getchar_crlf(fp, boundaries, btp)
693 register FILE *fp;
694 char **boundaries;
695 int *btp;
696 {
697 static bool sendlf = FALSE;
698 int c;
699
700 if (sendlf)
701 {
702 sendlf = FALSE;
703 return '\n';
704 }
705 c = mime_getchar(fp, boundaries, btp);
706 if (c == '\n')
707 {
708 sendlf = TRUE;
709 return '\r';
710 }
711 return c;
712 }
713 /*
714 ** MIMEBOUNDARY -- determine if this line is a MIME boundary & its type
715 **
716 ** Parameters:
717 ** line -- the input line.
718 ** boundaries -- the set of currently pending boundaries.
719 **
720 ** Returns:
721 ** MBT_NOTSEP -- if this is not a separator line
722 ** MBT_INTERMED -- if this is an intermediate separator
723 ** MBT_FINAL -- if this is a final boundary
724 ** MBT_SYNTAX -- if this is a boundary for the wrong
725 ** enclosure -- i.e., a syntax error.
726 */
727
728 int
mimeboundary(line,boundaries)729 mimeboundary(line, boundaries)
730 register char *line;
731 char **boundaries;
732 {
733 int type = MBT_NOTSEP;
734 int i;
735 int savec;
736
737 if (line[0] != '-' || line[1] != '-' || boundaries == NULL)
738 return MBT_NOTSEP;
739 i = strlen(line);
740 if (line[i - 1] == '\n')
741 i--;
742
743 /* strip off trailing whitespace */
744 while (line[i - 1] == ' ' || line[i - 1] == '\t')
745 i--;
746 savec = line[i];
747 line[i] = '\0';
748
749 if (tTd(43, 5))
750 printf("mimeboundary: line=\"%s\"... ", line);
751
752 /* check for this as an intermediate boundary */
753 if (isboundary(&line[2], boundaries) >= 0)
754 type = MBT_INTERMED;
755 else if (i > 2 && strncmp(&line[i - 2], "--", 2) == 0)
756 {
757 /* check for a final boundary */
758 line[i - 2] = '\0';
759 if (isboundary(&line[2], boundaries) >= 0)
760 type = MBT_FINAL;
761 line[i - 2] = '-';
762 }
763
764 line[i] = savec;
765 if (tTd(43, 5))
766 printf("%s\n", MimeBoundaryNames[type]);
767 return type;
768 }
769 /*
770 ** DEFCHARSET -- return default character set for message
771 **
772 ** The first choice for character set is for the mailer
773 ** corresponding to the envelope sender. If neither that
774 ** nor the global configuration file has a default character
775 ** set defined, return "unknown-8bit" as recommended by
776 ** RFC 1428 section 3.
777 **
778 ** Parameters:
779 ** e -- the envelope for this message.
780 **
781 ** Returns:
782 ** The default character set for that mailer.
783 */
784
785 char *
defcharset(e)786 defcharset(e)
787 register ENVELOPE *e;
788 {
789 if (e != NULL && e->e_from.q_mailer != NULL &&
790 e->e_from.q_mailer->m_defcharset != NULL)
791 return e->e_from.q_mailer->m_defcharset;
792 if (DefaultCharSet != NULL)
793 return DefaultCharSet;
794 return "unknown-8bit";
795 }
796 /*
797 ** ISBOUNDARY -- is a given string a currently valid boundary?
798 **
799 ** Parameters:
800 ** line -- the current input line.
801 ** boundaries -- the list of valid boundaries.
802 **
803 ** Returns:
804 ** The index number in boundaries if the line is found.
805 ** -1 -- otherwise.
806 **
807 */
808
809 int
isboundary(line,boundaries)810 isboundary(line, boundaries)
811 char *line;
812 char **boundaries;
813 {
814 register int i;
815
816 for (i = 0; boundaries[i] != NULL; i++)
817 {
818 if (strcmp(line, boundaries[i]) == 0)
819 return i;
820 }
821 return -1;
822 }
823
824 #endif /* MIME */
825