167545Seric /* 267545Seric * Copyright (c) 1994 Eric P. Allman 367545Seric * Copyright (c) 1994 467545Seric * The Regents of the University of California. All rights reserved. 567545Seric * 667545Seric * %sccs.include.redist.c% 767545Seric */ 867545Seric 967545Seric # include "sendmail.h" 1067545Seric # include <string.h> 1167545Seric 1267545Seric #ifndef lint 13*68517Seric static char sccsid[] = "@(#)mime.c 8.11 (Berkeley) 03/11/95"; 1467545Seric #endif /* not lint */ 1567545Seric 1667545Seric /* 1767545Seric ** MIME support. 1867545Seric ** 1967545Seric ** I am indebted to John Beck of Hewlett-Packard, who contributed 2067545Seric ** his code to me for inclusion. As it turns out, I did not use 2167545Seric ** his code since he used a "minimum change" approach that used 2267545Seric ** several temp files, and I wanted a "minimum impact" approach 2367545Seric ** that would avoid copying. However, looking over his code 2467545Seric ** helped me cement my understanding of the problem. 2567545Seric ** 2667545Seric ** I also looked at, but did not directly use, Nathaniel 2767545Seric ** Borenstein's "code.c" module. Again, it functioned as 2867545Seric ** a file-to-file translator, which did not fit within my 2967545Seric ** design bounds, but it was a useful base for understanding 3067545Seric ** the problem. 3167545Seric */ 3267545Seric 3367545Seric 3467545Seric /* character set for hex and base64 encoding */ 3567545Seric char Base16Code[] = "0123456789ABCDEF"; 3667545Seric char Base64Code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 3767545Seric 3867545Seric /* types of MIME boundaries */ 3967545Seric #define MBT_SYNTAX 0 /* syntax error */ 4067545Seric #define MBT_NOTSEP 1 /* not a boundary */ 4167545Seric #define MBT_INTERMED 2 /* intermediate boundary (no trailing --) */ 4267545Seric #define MBT_FINAL 3 /* final boundary (trailing -- included) */ 4367547Seric 4467547Seric static int MimeBoundaryType; /* internal linkage */ 4567545Seric /* 4667545Seric ** MIME8TO7 -- output 8 bit body in 7 bit format 4767545Seric ** 4867545Seric ** The header has already been output -- this has to do the 4967545Seric ** 8 to 7 bit conversion. It would be easy if we didn't have 5067545Seric ** to deal with nested formats (multipart/xxx and message/rfc822). 5167545Seric ** 5267545Seric ** We won't be called if we don't have to do a conversion, and 5367545Seric ** appropriate MIME-Version: and Content-Type: fields have been 5467545Seric ** output. Any Content-Transfer-Encoding: field has not been 5567545Seric ** output, and we can add it here. 5667545Seric ** 5767545Seric ** Parameters: 5867545Seric ** mci -- mailer connection information. 5967545Seric ** header -- the header for this body part. 6067545Seric ** e -- envelope. 61*68517Seric ** boundaries -- the currently pending message boundaries. 62*68517Seric ** NULL if we are processing the outer portion. 63*68517Seric ** flags -- to tweak processing. 6467545Seric ** 6567545Seric ** Returns: 6667545Seric ** An indicator of what terminated the message part: 6767545Seric ** MBT_FINAL -- the final boundary 6867545Seric ** MBT_INTERMED -- an intermediate boundary 6967545Seric ** MBT_NOTSEP -- an end of file 7067545Seric */ 7167545Seric 72*68517Seric struct args 73*68517Seric { 74*68517Seric char *field; /* name of field */ 75*68517Seric char *value; /* value of that field */ 76*68517Seric }; 77*68517Seric 7867545Seric int 79*68517Seric mime8to7(mci, header, e, boundaries, flags) 8067545Seric register MCI *mci; 8168515Seric HDR *header; register ENVELOPE *e; 82*68517Seric char **boundaries; 83*68517Seric int flags; 8467545Seric { 8567545Seric register char *p; 8667545Seric int linelen; 8767545Seric int bt; 8867545Seric off_t offset; 8967545Seric size_t sectionsize, sectionhighbits; 90*68517Seric int i; 91*68517Seric char *type; 92*68517Seric char *subtype; 93*68517Seric char **pvp; 94*68517Seric int argc = 0; 95*68517Seric struct args argv[MAXMIMEARGS]; 9667545Seric char bbuf[128]; 9767545Seric char buf[MAXLINE]; 98*68517Seric char pvpbuf[MAXLINE]; 9967545Seric 10067545Seric if (tTd(43, 1)) 10167545Seric { 10267545Seric printf("mime8to7: boundary=%s\n", 103*68517Seric boundaries[0] == NULL ? "<none>" : boundaries[0]); 104*68517Seric for (i = 1; boundaries[i] != NULL; i++) 105*68517Seric printf("\tboundaries[i]\n"); 10667545Seric } 107*68517Seric type = subtype = "-none-"; 10867545Seric p = hvalue("Content-Type", header); 109*68517Seric if (p != NULL && 110*68517Seric (pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL)) != NULL && 111*68517Seric pvp[0] != NULL) 11267545Seric { 113*68517Seric type = *pvp++; 114*68517Seric if (*pvp != NULL && strcmp(*pvp, "/") == 0 && 115*68517Seric *++pvp != NULL) 116*68517Seric { 117*68517Seric subtype = *pvp++; 118*68517Seric } 119*68517Seric 120*68517Seric /* break out parameters */ 121*68517Seric while (*pvp != NULL && argc < MAXMIMEARGS) 122*68517Seric { 123*68517Seric /* skip to semicolon separator */ 124*68517Seric while (*pvp != NULL && strcmp(*pvp, ";") != 0) 125*68517Seric pvp++; 126*68517Seric if (*pvp++ == NULL || *pvp == NULL) 127*68517Seric break; 128*68517Seric 129*68517Seric /* extract field name */ 130*68517Seric argv[argc].field = *pvp++; 131*68517Seric 132*68517Seric /* see if there is a value */ 133*68517Seric if (*pvp != NULL && strcmp(*pvp, "=") == 0 && 134*68517Seric (*++pvp == NULL || strcmp(*pvp, ";") != 0)) 135*68517Seric { 136*68517Seric argv[argc].value = *pvp; 137*68517Seric argc++; 138*68517Seric } 139*68517Seric } 140*68517Seric } 141*68517Seric if (strcasecmp(type, "multipart") == 0) 142*68517Seric { 14367545Seric register char *q; 14467545Seric 145*68517Seric for (i = 0; i < argc; i++) 14667545Seric { 147*68517Seric if (strcasecmp(argv[i].field, "boundary") == 0) 148*68517Seric break; 149*68517Seric } 150*68517Seric if (i >= argc) 151*68517Seric { 15267545Seric syserr("mime8to7: Content-Type: %s missing boundary", p); 15367545Seric p = "---"; 15467545Seric } 15567545Seric else 156*68517Seric p = argv[i].value; 15767545Seric if (*p == '"') 15867545Seric q = strchr(p, '"'); 15967545Seric else 16067545Seric q = p + strlen(p); 16167545Seric if (q - p > sizeof bbuf - 1) 16267545Seric { 16367545Seric syserr("mime8to7: multipart boundary \"%.*s\" too long", 16467545Seric q - p, p); 16567545Seric q = p + sizeof bbuf - 1; 16667545Seric } 16767545Seric strncpy(bbuf, p, q - p); 16867545Seric bbuf[q - p] = '\0'; 16967545Seric if (tTd(43, 1)) 17067545Seric { 17167545Seric printf("mime8to7: multipart boundary \"%s\"\n", bbuf); 17267545Seric } 173*68517Seric for (i = 0; i < MAXMIMENESTING; i++) 174*68517Seric if (boundaries[i] == NULL) 175*68517Seric break; 176*68517Seric if (i >= MAXMIMENESTING) 177*68517Seric syserr("mime8to7: multipart nesting boundary too deep"); 178*68517Seric else 179*68517Seric { 180*68517Seric boundaries[i] = bbuf; 181*68517Seric boundaries[i + 1] = NULL; 182*68517Seric } 18367545Seric 184*68517Seric /* flag subtypes that can't have any 8-bit data */ 185*68517Seric if (strcasecmp(subtype, "signed") == 0) 186*68517Seric flags |= M87F_NO8BIT; 187*68517Seric 18867545Seric /* skip the early "comment" prologue */ 18967545Seric bt = MBT_FINAL; 19067545Seric while (fgets(buf, sizeof buf, e->e_dfp) != NULL) 19167545Seric { 192*68517Seric bt = mimeboundary(buf, boundaries); 19367545Seric if (bt != MBT_NOTSEP) 19467545Seric break; 19567545Seric putline(buf, mci); 19667545Seric } 19767545Seric while (bt != MBT_FINAL) 19867545Seric { 19967545Seric auto HDR *hdr = NULL; 20067545Seric 20167545Seric sprintf(buf, "--%s", bbuf); 20267545Seric putline(buf, mci); 20367545Seric collect(e->e_dfp, FALSE, FALSE, &hdr, e); 20467936Seric putheader(mci, hdr, e, 0); 205*68517Seric bt = mime8to7(mci, hdr, e, boundaries, flags); 20667545Seric } 20767545Seric sprintf(buf, "--%s--", bbuf); 20867545Seric putline(buf, mci); 20967545Seric 21067545Seric /* skip the late "comment" epilogue */ 21167545Seric while (fgets(buf, sizeof buf, e->e_dfp) != NULL) 21267545Seric { 21367545Seric putline(buf, mci); 214*68517Seric bt = mimeboundary(buf, boundaries); 21567545Seric if (bt != MBT_NOTSEP) 21667545Seric break; 21767545Seric } 218*68517Seric boundaries[i] = NULL; 21967545Seric return bt; 22067545Seric } 22167545Seric 22267545Seric /* 22367545Seric ** Non-compound body type 22467545Seric ** 22567545Seric ** Compute the ratio of seven to eight bit characters; 22667545Seric ** use that as a heuristic to decide how to do the 22767545Seric ** encoding. 22867545Seric */ 22967545Seric 230*68517Seric /* handle types that cannot have 8-bit data internally */ 231*68517Seric sprintf(buf, "%s/%s", type, subtype); 232*68517Seric if (wordinclass(buf, 'n')) 233*68517Seric flags |= M87F_NO8BIT; 234*68517Seric 23567545Seric sectionsize = sectionhighbits = 0; 236*68517Seric if (!bitset(M87F_NO8BIT, flags)) 23767545Seric { 23868515Seric /* remember where we were */ 23968515Seric offset = ftell(e->e_dfp); 24068515Seric if (offset == -1) 24168515Seric syserr("mime8to7: cannot ftell on %s", e->e_df); 24268515Seric 24368515Seric /* do a scan of this body type to count character types */ 24468515Seric while (fgets(buf, sizeof buf, e->e_dfp) != NULL) 24567545Seric { 246*68517Seric bt = mimeboundary(buf, boundaries); 24768515Seric if (bt != MBT_NOTSEP) 24868515Seric break; 24968515Seric for (p = buf; *p != '\0'; p++) 25068515Seric { 25168515Seric /* count bytes with the high bit set */ 25268515Seric sectionsize++; 25368515Seric if (bitset(0200, *p)) 25468515Seric sectionhighbits++; 25568515Seric } 25668515Seric 25768515Seric /* 25868515Seric ** Heuristic: if 1/4 of the first 4K bytes are 8-bit, 25968515Seric ** assume base64. This heuristic avoids double-reading 26068515Seric ** large graphics or video files. 26168515Seric */ 26268515Seric 26368515Seric if (sectionsize >= 4096 && 26468515Seric sectionhighbits > sectionsize / 4) 26568515Seric break; 26667545Seric } 26768515Seric if (feof(e->e_dfp)) 26868515Seric bt = MBT_FINAL; 26967547Seric 27068515Seric /* return to the original offset for processing */ 27168515Seric /* XXX use relative seeks to handle >31 bit file sizes? */ 27268515Seric if (fseek(e->e_dfp, offset, SEEK_SET) < 0) 27368515Seric syserr("mime8to7: cannot fseek on %s", e->e_df); 27467545Seric } 27567545Seric 27667547Seric /* 27767547Seric ** Heuristically determine encoding method. 27867547Seric ** If more than 1/8 of the total characters have the 27967547Seric ** eighth bit set, use base64; else use quoted-printable. 28067547Seric */ 28167547Seric 28267545Seric if (tTd(43, 8)) 28367545Seric { 28467545Seric printf("mime8to7: %ld high bits in %ld bytes\n", 28567545Seric sectionhighbits, sectionsize); 28667545Seric } 28767554Seric if (sectionhighbits == 0) 28867545Seric { 28967554Seric /* no encoding necessary */ 29067695Seric p = hvalue("content-transfer-encoding", header); 29167695Seric if (p != NULL) 29267695Seric { 29367695Seric sprintf(buf, "Content-Transfer-Encoding: %s", p); 29467695Seric putline(buf, mci); 29567695Seric } 29667554Seric putline("", mci); 29767554Seric mci->mci_flags &= ~MCIF_INHEADER; 29867554Seric while (fgets(buf, sizeof buf, e->e_dfp) != NULL) 29967554Seric { 300*68517Seric bt = mimeboundary(buf, boundaries); 30167554Seric if (bt != MBT_NOTSEP) 30267554Seric break; 30367554Seric if (buf[0] == 'F' && 30467554Seric bitnset(M_ESCFROM, mci->mci_mailer->m_flags) && 30567554Seric strncmp(buf, "From ", 5) == 0) 30667554Seric (void) putc('>', mci->mci_out); 30767554Seric putline(buf, mci); 30867554Seric } 30967554Seric } 31067554Seric else if (sectionsize / 8 < sectionhighbits) 31167554Seric { 31267545Seric /* use base64 encoding */ 31367545Seric int c1, c2; 31467545Seric 31567545Seric putline("Content-Transfer-Encoding: base64", mci); 31667545Seric putline("", mci); 31767545Seric mci->mci_flags &= ~MCIF_INHEADER; 31867545Seric linelen = 0; 319*68517Seric while ((c1 = mime_getchar(e->e_dfp, boundaries)) != EOF) 32067545Seric { 32167545Seric if (linelen > 71) 32267545Seric { 32367545Seric fputs(mci->mci_mailer->m_eol, mci->mci_out); 32467545Seric linelen = 0; 32567545Seric } 32667545Seric linelen += 4; 32767545Seric fputc(Base64Code[c1 >> 2], mci->mci_out); 32867545Seric c1 = (c1 & 0x03) << 4; 329*68517Seric c2 = mime_getchar(e->e_dfp, boundaries); 33067545Seric if (c2 == EOF) 33167545Seric { 33267545Seric fputc(Base64Code[c1], mci->mci_out); 33367545Seric fputc('=', mci->mci_out); 33467545Seric fputc('=', mci->mci_out); 33567545Seric break; 33667545Seric } 33767545Seric c1 |= (c2 >> 4) & 0x0f; 33867545Seric fputc(Base64Code[c1], mci->mci_out); 33967545Seric c1 = (c2 & 0x0f) << 2; 340*68517Seric c2 = mime_getchar(e->e_dfp, boundaries); 34167545Seric if (c2 == EOF) 34267545Seric { 34367545Seric fputc(Base64Code[c1], mci->mci_out); 34467545Seric fputc('=', mci->mci_out); 34567545Seric break; 34667545Seric } 34767545Seric c1 |= (c2 >> 6) & 0x03; 34867545Seric fputc(Base64Code[c1], mci->mci_out); 34967545Seric fputc(Base64Code[c2 & 0x3f], mci->mci_out); 35067545Seric } 35167545Seric } 35267545Seric else 35367545Seric { 35467545Seric /* use quoted-printable encoding */ 35567545Seric int c1, c2; 35668515Seric int fromstate; 35767545Seric 35867545Seric putline("Content-Transfer-Encoding: quoted-printable", mci); 35967545Seric putline("", mci); 36067545Seric mci->mci_flags &= ~MCIF_INHEADER; 36168515Seric linelen = fromstate = 0; 36267554Seric c2 = '\n'; 363*68517Seric while ((c1 = mime_getchar(e->e_dfp, boundaries)) != EOF) 36467545Seric { 36567545Seric if (c1 == '\n') 36667545Seric { 36767545Seric if (c2 == ' ' || c2 == '\t') 36867545Seric { 36967545Seric fputc('=', mci->mci_out); 37067840Seric fputc(Base16Code[(c2 >> 4) & 0x0f], 37167840Seric mci->mci_out); 37267840Seric fputc(Base16Code[c2 & 0x0f], 37367840Seric mci->mci_out); 37467840Seric fputs(mci->mci_mailer->m_eol, 37567840Seric mci->mci_out); 37667545Seric } 37767545Seric fputs(mci->mci_mailer->m_eol, mci->mci_out); 37868515Seric linelen = fromstate = 0; 37967545Seric c2 = c1; 38067545Seric continue; 38167545Seric } 38268515Seric if (c2 == ' ' && linelen == 4 && fromstate == 4 && 38368515Seric bitnset(M_ESCFROM, mci->mci_mailer->m_flags)) 38467840Seric { 38568515Seric fputs("=20", mci->mci_out); 38668515Seric linelen += 3; 38768515Seric } 38868515Seric else if (c2 == ' ' || c2 == '\t') 38968515Seric { 39067840Seric fputc(c2, mci->mci_out); 39167840Seric linelen++; 39267840Seric } 39367545Seric if (linelen > 72) 39467545Seric { 39567545Seric fputc('=', mci->mci_out); 39667545Seric fputs(mci->mci_mailer->m_eol, mci->mci_out); 39768515Seric linelen = fromstate = 0; 39867554Seric c2 = '\n'; 39967545Seric } 40067761Seric if (c2 == '\n' && c1 == '.' && 40167761Seric bitnset(M_XDOT, mci->mci_mailer->m_flags)) 40267761Seric { 40367761Seric fputc('.', mci->mci_out); 40467761Seric linelen++; 40567761Seric } 40667547Seric if ((c1 < 0x20 && c1 != '\t') || c1 >= 0x7f || c1 == '=') 40767545Seric { 40867545Seric fputc('=', mci->mci_out); 40967545Seric fputc(Base16Code[(c1 >> 4) & 0x0f], mci->mci_out); 41067545Seric fputc(Base16Code[c1 & 0x0f], mci->mci_out); 41167545Seric linelen += 3; 41267545Seric } 41367840Seric else if (c1 != ' ' && c1 != '\t') 41467545Seric { 41568515Seric if (linelen < 4 && c1 == "From"[linelen]) 41668515Seric fromstate++; 41767545Seric fputc(c1, mci->mci_out); 41867545Seric linelen++; 41967545Seric } 42067545Seric c2 = c1; 42167545Seric } 42267840Seric 42367840Seric /* output any saved character */ 42467840Seric if (c2 == ' ' || c2 == '\t') 42567840Seric { 42668515Seric fputc('=', mci->mci_out); 42768515Seric fputc(Base16Code[(c2 >> 4) & 0x0f], mci->mci_out); 42868515Seric fputc(Base16Code[c2 & 0x0f], mci->mci_out); 42968515Seric linelen += 3; 43067840Seric } 43167545Seric } 43267545Seric if (linelen > 0) 43367545Seric fputs(mci->mci_mailer->m_eol, mci->mci_out); 43467547Seric return MimeBoundaryType; 43567545Seric } 43668515Seric /* 43768515Seric ** MIME_GETCHAR -- get a character for MIME processing 43868515Seric ** 43968515Seric ** Treats boundaries as EOF. 44068515Seric ** 44168515Seric ** Parameters: 44268515Seric ** fp -- the input file. 443*68517Seric ** boundaries -- the current MIME boundaries. 44468515Seric ** 44568515Seric ** Returns: 44668515Seric ** The next character in the input stream. 44768515Seric */ 44867545Seric 44967545Seric int 450*68517Seric mime_getchar(fp, boundaries) 45167545Seric register FILE *fp; 452*68517Seric char **boundaries; 45367545Seric { 45467545Seric int c; 45567545Seric static char *bp = NULL; 45667545Seric static int buflen = 0; 45767545Seric static bool atbol = TRUE; /* at beginning of line */ 45867545Seric static char buf[128]; /* need not be a full line */ 45967545Seric 46067545Seric if (buflen > 0) 46167545Seric { 46267545Seric buflen--; 46367545Seric return *bp++; 46467545Seric } 46568515Seric bp = buf; 46668515Seric buflen = 0; 46767545Seric c = fgetc(fp); 46868515Seric if (c == '\n') 46968515Seric { 47068515Seric /* might be part of a MIME boundary */ 47168515Seric *bp++ = c; 47268515Seric atbol = TRUE; 47368515Seric c = fgetc(fp); 47468515Seric } 47568515Seric if (c != EOF) 47668515Seric *bp++ = c; 477*68517Seric if (atbol && c == '-') 47867545Seric { 47967545Seric /* check for a message boundary */ 48067545Seric c = fgetc(fp); 48167545Seric if (c != '-') 48267545Seric { 48367545Seric if (c != EOF) 48468515Seric *bp++ = c; 48568515Seric buflen = bp - buf - 1; 48668515Seric bp = buf; 48768515Seric return *bp++; 48867545Seric } 48967545Seric 49067545Seric /* got "--", now check for rest of separator */ 49167545Seric *bp++ = '-'; 49267545Seric while (bp < &buf[sizeof buf - 1] && 49367545Seric (c = fgetc(fp)) != EOF && c != '\n') 49467545Seric { 49567545Seric *bp++ = c; 49667545Seric } 49767545Seric *bp = '\0'; 498*68517Seric MimeBoundaryType = mimeboundary(buf, boundaries); 49967547Seric switch (MimeBoundaryType) 50067545Seric { 50167545Seric case MBT_FINAL: 50267545Seric case MBT_INTERMED: 50367545Seric /* we have a message boundary */ 50467545Seric buflen = 0; 50567545Seric return EOF; 50667545Seric } 50767545Seric 50867545Seric atbol = c == '\n'; 50967545Seric if (c != EOF) 51067545Seric *bp++ = c; 51167545Seric } 51267545Seric 51368515Seric buflen = bp - buf - 1; 51468515Seric if (buflen < 0) 51568515Seric return EOF; 51668515Seric bp = buf; 51768515Seric return *bp++; 51867545Seric } 51967545Seric /* 52067545Seric ** MIMEBOUNDARY -- determine if this line is a MIME boundary & its type 52167545Seric ** 52267545Seric ** Parameters: 52367545Seric ** line -- the input line. 524*68517Seric ** boundaries -- the set of currently pending boundaries. 52567545Seric ** 52667545Seric ** Returns: 52767545Seric ** MBT_NOTSEP -- if this is not a separator line 52867545Seric ** MBT_INTERMED -- if this is an intermediate separator 52967545Seric ** MBT_FINAL -- if this is a final boundary 53067545Seric ** MBT_SYNTAX -- if this is a boundary for the wrong 53167545Seric ** enclosure -- i.e., a syntax error. 53267545Seric */ 53367545Seric 53467545Seric int 535*68517Seric mimeboundary(line, boundaries) 53667545Seric register char *line; 537*68517Seric char **boundaries; 53867545Seric { 53967545Seric int type; 54067545Seric int i; 541*68517Seric int savec; 54267545Seric 543*68517Seric if (line[0] != '-' || line[1] != '-' || boundaries == NULL) 54467545Seric return MBT_NOTSEP; 54567545Seric if (tTd(43, 5)) 546*68517Seric printf("mimeboundary: line=\"%s\"... ", line); 54767545Seric i = strlen(line); 54867545Seric if (line[i - 1] == '\n') 54967545Seric i--; 55068515Seric while (line[i - 1] == ' ' || line[i - 1] == '\t') 55168515Seric i--; 55267545Seric if (i > 2 && strncmp(&line[i - 2], "--", 2) == 0) 55367545Seric { 55467545Seric type = MBT_FINAL; 55567545Seric i -= 2; 55667545Seric } 55767545Seric else 55867545Seric type = MBT_INTERMED; 55967545Seric 560*68517Seric savec = line[i]; 561*68517Seric line[i] = '\0'; 56267545Seric /* XXX should check for improper nesting here */ 563*68517Seric if (isboundary(&line[2], boundaries) < 0) 56467545Seric type = MBT_NOTSEP; 565*68517Seric line[i] = savec; 56667545Seric if (tTd(43, 5)) 56767545Seric printf("%d\n", type); 56867545Seric return type; 56967545Seric } 57067896Seric /* 57167896Seric ** DEFCHARSET -- return default character set for message 57267896Seric ** 57367896Seric ** The first choice for character set is for the mailer 57467896Seric ** corresponding to the envelope sender. If neither that 57567896Seric ** nor the global configuration file has a default character 57667896Seric ** set defined, return "unknown-8bit" as recommended by 57767896Seric ** RFC 1428 section 3. 57867896Seric ** 57967896Seric ** Parameters: 58067896Seric ** e -- the envelope for this message. 58167896Seric ** 58267896Seric ** Returns: 58367896Seric ** The default character set for that mailer. 58467896Seric */ 58567896Seric 58667896Seric char * 58767896Seric defcharset(e) 58867896Seric register ENVELOPE *e; 58967896Seric { 59067896Seric if (e != NULL && e->e_from.q_mailer != NULL && 59167896Seric e->e_from.q_mailer->m_defcharset != NULL) 59267896Seric return e->e_from.q_mailer->m_defcharset; 59367896Seric if (DefaultCharSet != NULL) 59467896Seric return DefaultCharSet; 59567896Seric return "unknown-8bit"; 59667896Seric } 597*68517Seric /* 598*68517Seric ** ISBOUNDARY -- is a given string a currently valid boundary? 599*68517Seric ** 600*68517Seric ** Parameters: 601*68517Seric ** line -- the current input line. 602*68517Seric ** boundaries -- the list of valid boundaries. 603*68517Seric ** 604*68517Seric ** Returns: 605*68517Seric ** The index number in boundaries if the line is found. 606*68517Seric ** -1 -- otherwise. 607*68517Seric ** 608*68517Seric */ 609*68517Seric 610*68517Seric int 611*68517Seric isboundary(line, boundaries) 612*68517Seric char *line; 613*68517Seric char **boundaries; 614*68517Seric { 615*68517Seric register int i; 616*68517Seric 617*68517Seric i = 0; 618*68517Seric while (boundaries[i] != NULL) 619*68517Seric { 620*68517Seric if (strcmp(line, boundaries[i]) == 0) 621*68517Seric return i; 622*68517Seric } 623*68517Seric return -1; 624*68517Seric } 625