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*68717Seric static char sccsid[] = "@(#)mime.c 8.14 (Berkeley) 04/03/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 44*68717Seric static char *MimeBoundaryNames[] = 45*68717Seric { 46*68717Seric "SYNTAX", "NOTSEP", "INTERMED", "FINAL" 47*68717Seric }; 4867545Seric /* 4967545Seric ** MIME8TO7 -- output 8 bit body in 7 bit format 5067545Seric ** 5167545Seric ** The header has already been output -- this has to do the 5267545Seric ** 8 to 7 bit conversion. It would be easy if we didn't have 5367545Seric ** to deal with nested formats (multipart/xxx and message/rfc822). 5467545Seric ** 5567545Seric ** We won't be called if we don't have to do a conversion, and 5667545Seric ** appropriate MIME-Version: and Content-Type: fields have been 5767545Seric ** output. Any Content-Transfer-Encoding: field has not been 5867545Seric ** output, and we can add it here. 5967545Seric ** 6067545Seric ** Parameters: 6167545Seric ** mci -- mailer connection information. 6267545Seric ** header -- the header for this body part. 6367545Seric ** e -- envelope. 6468517Seric ** boundaries -- the currently pending message boundaries. 6568517Seric ** NULL if we are processing the outer portion. 6668517Seric ** flags -- to tweak processing. 6767545Seric ** 6867545Seric ** Returns: 6967545Seric ** An indicator of what terminated the message part: 7067545Seric ** MBT_FINAL -- the final boundary 7167545Seric ** MBT_INTERMED -- an intermediate boundary 7267545Seric ** MBT_NOTSEP -- an end of file 7367545Seric */ 7467545Seric 7568517Seric struct args 7668517Seric { 7768517Seric char *field; /* name of field */ 7868517Seric char *value; /* value of that field */ 7968517Seric }; 8068517Seric 8167545Seric int 8268517Seric mime8to7(mci, header, e, boundaries, flags) 8367545Seric register MCI *mci; 84*68717Seric HDR *header; 85*68717Seric register ENVELOPE *e; 8668517Seric char **boundaries; 8768517Seric int flags; 8867545Seric { 8967545Seric register char *p; 9067545Seric int linelen; 9167545Seric int bt; 9267545Seric off_t offset; 9367545Seric size_t sectionsize, sectionhighbits; 9468517Seric int i; 9568517Seric char *type; 9668517Seric char *subtype; 9768517Seric char **pvp; 9868517Seric int argc = 0; 9968517Seric struct args argv[MAXMIMEARGS]; 10067545Seric char bbuf[128]; 10167545Seric char buf[MAXLINE]; 10268517Seric char pvpbuf[MAXLINE]; 10368711Seric extern char MimeTokenTab[256]; 10467545Seric 10567545Seric if (tTd(43, 1)) 10667545Seric { 107*68717Seric printf("mime8to7: flags = %x, boundaries =", flags); 108*68717Seric if (boundaries[0] == NULL) 109*68717Seric printf(" <none>"); 110*68717Seric else 111*68717Seric { 112*68717Seric for (i = 0; boundaries[i] != NULL; i++) 113*68717Seric printf(" %s", boundaries[i]); 114*68717Seric } 115*68717Seric printf("\n"); 11667545Seric } 11768517Seric type = subtype = "-none-"; 11867545Seric p = hvalue("Content-Type", header); 11968517Seric if (p != NULL && 12068711Seric (pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL, 12168711Seric MimeTokenTab)) != NULL && 12268517Seric pvp[0] != NULL) 12367545Seric { 124*68717Seric if (tTd(43, 40)) 125*68717Seric { 126*68717Seric for (i = 0; pvp[i] != NULL; i++) 127*68717Seric printf("pvp[%d] = \"%s\"\n", i, pvp[i]); 128*68717Seric } 12968517Seric type = *pvp++; 13068517Seric if (*pvp != NULL && strcmp(*pvp, "/") == 0 && 13168517Seric *++pvp != NULL) 13268517Seric { 13368517Seric subtype = *pvp++; 13468517Seric } 13568517Seric 13668517Seric /* break out parameters */ 13768517Seric while (*pvp != NULL && argc < MAXMIMEARGS) 13868517Seric { 13968517Seric /* skip to semicolon separator */ 14068517Seric while (*pvp != NULL && strcmp(*pvp, ";") != 0) 14168517Seric pvp++; 14268517Seric if (*pvp++ == NULL || *pvp == NULL) 14368517Seric break; 14468517Seric 14568517Seric /* extract field name */ 14668517Seric argv[argc].field = *pvp++; 14768517Seric 14868517Seric /* see if there is a value */ 14968517Seric if (*pvp != NULL && strcmp(*pvp, "=") == 0 && 15068517Seric (*++pvp == NULL || strcmp(*pvp, ";") != 0)) 15168517Seric { 15268517Seric argv[argc].value = *pvp; 15368517Seric argc++; 15468517Seric } 15568517Seric } 15668517Seric } 157*68717Seric 158*68717Seric /* handle types that cannot have 8-bit data internally */ 159*68717Seric sprintf(buf, "%s/%s", type, subtype); 160*68717Seric if (wordinclass(buf, 'n')) 161*68717Seric flags |= M87F_NO8BIT; 162*68717Seric 163*68717Seric /* 164*68717Seric ** Multipart requires special processing. 165*68717Seric ** 166*68717Seric ** Do a recursive descent into the message. 167*68717Seric */ 168*68717Seric 16968517Seric if (strcasecmp(type, "multipart") == 0) 17068517Seric { 17167545Seric register char *q; 17267545Seric 17368517Seric for (i = 0; i < argc; i++) 17467545Seric { 17568517Seric if (strcasecmp(argv[i].field, "boundary") == 0) 17668517Seric break; 17768517Seric } 17868517Seric if (i >= argc) 17968517Seric { 18067545Seric syserr("mime8to7: Content-Type: %s missing boundary", p); 18167545Seric p = "---"; 18267545Seric } 18367545Seric else 18468517Seric p = argv[i].value; 18567545Seric if (*p == '"') 18668711Seric q = strchr(++p, '"'); 18767545Seric else 18867545Seric q = p + strlen(p); 18967545Seric if (q - p > sizeof bbuf - 1) 19067545Seric { 19167545Seric syserr("mime8to7: multipart boundary \"%.*s\" too long", 19267545Seric q - p, p); 19367545Seric q = p + sizeof bbuf - 1; 19467545Seric } 19567545Seric strncpy(bbuf, p, q - p); 19667545Seric bbuf[q - p] = '\0'; 19767545Seric if (tTd(43, 1)) 19867545Seric printf("mime8to7: multipart boundary \"%s\"\n", bbuf); 19968517Seric for (i = 0; i < MAXMIMENESTING; i++) 20068517Seric if (boundaries[i] == NULL) 20168517Seric break; 20268517Seric if (i >= MAXMIMENESTING) 20368517Seric syserr("mime8to7: multipart nesting boundary too deep"); 20468517Seric else 20568517Seric { 20668517Seric boundaries[i] = bbuf; 20768517Seric boundaries[i + 1] = NULL; 20868517Seric } 20967545Seric 21067545Seric /* skip the early "comment" prologue */ 211*68717Seric putline("", mci); 21267545Seric while (fgets(buf, sizeof buf, e->e_dfp) != NULL) 21367545Seric { 21468517Seric bt = mimeboundary(buf, boundaries); 21567545Seric if (bt != MBT_NOTSEP) 21667545Seric break; 21767545Seric putline(buf, mci); 218*68717Seric if (tTd(43, 99)) 219*68717Seric printf(" ...%s", buf); 22067545Seric } 221*68717Seric if (feof(e->e_dfp)) 222*68717Seric bt = MBT_FINAL; 22367545Seric while (bt != MBT_FINAL) 22467545Seric { 22567545Seric auto HDR *hdr = NULL; 22667545Seric 22767545Seric sprintf(buf, "--%s", bbuf); 22867545Seric putline(buf, mci); 229*68717Seric if (tTd(43, 35)) 230*68717Seric printf(" ...%s\n", buf); 23167545Seric collect(e->e_dfp, FALSE, FALSE, &hdr, e); 232*68717Seric if (tTd(43, 101)) 233*68717Seric putline("+++after collect", mci); 23467936Seric putheader(mci, hdr, e, 0); 235*68717Seric if (tTd(43, 101)) 236*68717Seric putline("+++after putheader", mci); 23768517Seric bt = mime8to7(mci, hdr, e, boundaries, flags); 23867545Seric } 23967545Seric sprintf(buf, "--%s--", bbuf); 24067545Seric putline(buf, mci); 241*68717Seric if (tTd(43, 35)) 242*68717Seric printf(" ...%s\n", buf); 243*68717Seric boundaries[i] = NULL; 24467545Seric 24567545Seric /* skip the late "comment" epilogue */ 24667545Seric while (fgets(buf, sizeof buf, e->e_dfp) != NULL) 24767545Seric { 24868517Seric bt = mimeboundary(buf, boundaries); 24967545Seric if (bt != MBT_NOTSEP) 25067545Seric break; 251*68717Seric putline(buf, mci); 252*68717Seric if (tTd(43, 99)) 253*68717Seric printf(" ...%s", buf); 25467545Seric } 255*68717Seric if (feof(e->e_dfp)) 256*68717Seric bt = MBT_FINAL; 257*68717Seric if (tTd(43, 3)) 258*68717Seric printf("\t\t\tmime8to7=>%s (multipart)\n", 259*68717Seric MimeBoundaryNames[bt]); 26067545Seric return bt; 26167545Seric } 26267545Seric 26367545Seric /* 26467545Seric ** Non-compound body type 26567545Seric ** 26667545Seric ** Compute the ratio of seven to eight bit characters; 26767545Seric ** use that as a heuristic to decide how to do the 26867545Seric ** encoding. 26967545Seric */ 27067545Seric 27167545Seric sectionsize = sectionhighbits = 0; 27268517Seric if (!bitset(M87F_NO8BIT, flags)) 27367545Seric { 27468515Seric /* remember where we were */ 27568515Seric offset = ftell(e->e_dfp); 27668515Seric if (offset == -1) 27768564Seric syserr("mime8to7: cannot ftell on df%s", e->e_id); 27868515Seric 27968515Seric /* do a scan of this body type to count character types */ 28068515Seric while (fgets(buf, sizeof buf, e->e_dfp) != NULL) 28167545Seric { 282*68717Seric if (mimeboundary(buf, boundaries) != MBT_NOTSEP) 28368515Seric break; 28468515Seric for (p = buf; *p != '\0'; p++) 28568515Seric { 28668515Seric /* count bytes with the high bit set */ 28768515Seric sectionsize++; 28868515Seric if (bitset(0200, *p)) 28968515Seric sectionhighbits++; 29068515Seric } 29168515Seric 29268515Seric /* 29368515Seric ** Heuristic: if 1/4 of the first 4K bytes are 8-bit, 29468515Seric ** assume base64. This heuristic avoids double-reading 29568515Seric ** large graphics or video files. 29668515Seric */ 29768515Seric 29868515Seric if (sectionsize >= 4096 && 29968515Seric sectionhighbits > sectionsize / 4) 30068515Seric break; 30167545Seric } 30267547Seric 30368515Seric /* return to the original offset for processing */ 30468515Seric /* XXX use relative seeks to handle >31 bit file sizes? */ 30568515Seric if (fseek(e->e_dfp, offset, SEEK_SET) < 0) 30668564Seric syserr("mime8to7: cannot fseek on df%s", e->e_id); 307*68717Seric else 308*68717Seric clearerr(e->e_dfp); 30967545Seric } 31067545Seric 31167547Seric /* 31267547Seric ** Heuristically determine encoding method. 31367547Seric ** If more than 1/8 of the total characters have the 31467547Seric ** eighth bit set, use base64; else use quoted-printable. 31567547Seric */ 31667547Seric 31767545Seric if (tTd(43, 8)) 31867545Seric { 319*68717Seric printf("mime8to7: %ld high bit(s) in %ld byte(s)\n", 32067545Seric sectionhighbits, sectionsize); 32167545Seric } 322*68717Seric linelen = 0; 32367554Seric if (sectionhighbits == 0) 32467545Seric { 32567554Seric /* no encoding necessary */ 32667695Seric p = hvalue("content-transfer-encoding", header); 32767695Seric if (p != NULL) 32867695Seric { 32967695Seric sprintf(buf, "Content-Transfer-Encoding: %s", p); 33067695Seric putline(buf, mci); 331*68717Seric if (tTd(43, 36)) 332*68717Seric printf(" ...%s\n", buf); 33367695Seric } 33467554Seric putline("", mci); 33567554Seric mci->mci_flags &= ~MCIF_INHEADER; 33667554Seric while (fgets(buf, sizeof buf, e->e_dfp) != NULL) 33767554Seric { 33868517Seric bt = mimeboundary(buf, boundaries); 33967554Seric if (bt != MBT_NOTSEP) 34067554Seric break; 34167554Seric if (buf[0] == 'F' && 34267554Seric bitnset(M_ESCFROM, mci->mci_mailer->m_flags) && 34367554Seric strncmp(buf, "From ", 5) == 0) 34467554Seric (void) putc('>', mci->mci_out); 34567554Seric putline(buf, mci); 34667554Seric } 347*68717Seric if (feof(e->e_dfp)) 348*68717Seric bt = MBT_FINAL; 34967554Seric } 35067554Seric else if (sectionsize / 8 < sectionhighbits) 35167554Seric { 35267545Seric /* use base64 encoding */ 35367545Seric int c1, c2; 35467545Seric 35567545Seric putline("Content-Transfer-Encoding: base64", mci); 356*68717Seric if (tTd(43, 36)) 357*68717Seric printf(" ...Content-Transfer-Encoding: base64\n"); 35867545Seric putline("", mci); 35967545Seric mci->mci_flags &= ~MCIF_INHEADER; 360*68717Seric while ((c1 = mime_getchar(e->e_dfp, boundaries, &bt)) != EOF) 36167545Seric { 36267545Seric if (linelen > 71) 36367545Seric { 36467545Seric fputs(mci->mci_mailer->m_eol, mci->mci_out); 36567545Seric linelen = 0; 36667545Seric } 36767545Seric linelen += 4; 36867545Seric fputc(Base64Code[c1 >> 2], mci->mci_out); 36967545Seric c1 = (c1 & 0x03) << 4; 370*68717Seric c2 = mime_getchar(e->e_dfp, boundaries, &bt); 37167545Seric if (c2 == EOF) 37267545Seric { 37367545Seric fputc(Base64Code[c1], mci->mci_out); 37467545Seric fputc('=', mci->mci_out); 37567545Seric fputc('=', mci->mci_out); 37667545Seric break; 37767545Seric } 37867545Seric c1 |= (c2 >> 4) & 0x0f; 37967545Seric fputc(Base64Code[c1], mci->mci_out); 38067545Seric c1 = (c2 & 0x0f) << 2; 381*68717Seric c2 = mime_getchar(e->e_dfp, boundaries, &bt); 38267545Seric if (c2 == EOF) 38367545Seric { 38467545Seric fputc(Base64Code[c1], mci->mci_out); 38567545Seric fputc('=', mci->mci_out); 38667545Seric break; 38767545Seric } 38867545Seric c1 |= (c2 >> 6) & 0x03; 38967545Seric fputc(Base64Code[c1], mci->mci_out); 39067545Seric fputc(Base64Code[c2 & 0x3f], mci->mci_out); 39167545Seric } 39267545Seric } 39367545Seric else 39467545Seric { 39567545Seric /* use quoted-printable encoding */ 39667545Seric int c1, c2; 39768515Seric int fromstate; 39867545Seric 39967545Seric putline("Content-Transfer-Encoding: quoted-printable", mci); 400*68717Seric if (tTd(43, 36)) 401*68717Seric printf(" ...Content-Transfer-Encoding: quoted-printable\n"); 40267545Seric putline("", mci); 40367545Seric mci->mci_flags &= ~MCIF_INHEADER; 404*68717Seric fromstate = 0; 40567554Seric c2 = '\n'; 406*68717Seric while ((c1 = mime_getchar(e->e_dfp, boundaries, &bt)) != EOF) 40767545Seric { 40867545Seric if (c1 == '\n') 40967545Seric { 41067545Seric if (c2 == ' ' || c2 == '\t') 41167545Seric { 41267545Seric fputc('=', mci->mci_out); 41367840Seric fputc(Base16Code[(c2 >> 4) & 0x0f], 41467840Seric mci->mci_out); 41567840Seric fputc(Base16Code[c2 & 0x0f], 41667840Seric mci->mci_out); 41767840Seric fputs(mci->mci_mailer->m_eol, 41867840Seric mci->mci_out); 41967545Seric } 42067545Seric fputs(mci->mci_mailer->m_eol, mci->mci_out); 42168515Seric linelen = fromstate = 0; 42267545Seric c2 = c1; 42367545Seric continue; 42467545Seric } 42568515Seric if (c2 == ' ' && linelen == 4 && fromstate == 4 && 42668515Seric bitnset(M_ESCFROM, mci->mci_mailer->m_flags)) 42767840Seric { 42868515Seric fputs("=20", mci->mci_out); 42968515Seric linelen += 3; 43068515Seric } 43168515Seric else if (c2 == ' ' || c2 == '\t') 43268515Seric { 43367840Seric fputc(c2, mci->mci_out); 43467840Seric linelen++; 43567840Seric } 43667545Seric if (linelen > 72) 43767545Seric { 43867545Seric fputc('=', mci->mci_out); 43967545Seric fputs(mci->mci_mailer->m_eol, mci->mci_out); 44068515Seric linelen = fromstate = 0; 44167554Seric c2 = '\n'; 44267545Seric } 44367761Seric if (c2 == '\n' && c1 == '.' && 44467761Seric bitnset(M_XDOT, mci->mci_mailer->m_flags)) 44567761Seric { 44667761Seric fputc('.', mci->mci_out); 44767761Seric linelen++; 44867761Seric } 44967547Seric if ((c1 < 0x20 && c1 != '\t') || c1 >= 0x7f || c1 == '=') 45067545Seric { 45167545Seric fputc('=', mci->mci_out); 45267545Seric fputc(Base16Code[(c1 >> 4) & 0x0f], mci->mci_out); 45367545Seric fputc(Base16Code[c1 & 0x0f], mci->mci_out); 45467545Seric linelen += 3; 45567545Seric } 45667840Seric else if (c1 != ' ' && c1 != '\t') 45767545Seric { 45868515Seric if (linelen < 4 && c1 == "From"[linelen]) 45968515Seric fromstate++; 46067545Seric fputc(c1, mci->mci_out); 46167545Seric linelen++; 46267545Seric } 46367545Seric c2 = c1; 46467545Seric } 46567840Seric 46667840Seric /* output any saved character */ 46767840Seric if (c2 == ' ' || c2 == '\t') 46867840Seric { 46968515Seric fputc('=', mci->mci_out); 47068515Seric fputc(Base16Code[(c2 >> 4) & 0x0f], mci->mci_out); 47168515Seric fputc(Base16Code[c2 & 0x0f], mci->mci_out); 47268515Seric linelen += 3; 47367840Seric } 47467545Seric } 47567545Seric if (linelen > 0) 47667545Seric fputs(mci->mci_mailer->m_eol, mci->mci_out); 477*68717Seric if (tTd(43, 3)) 478*68717Seric printf("\t\t\tmime8to7=>%s (basic)\n", MimeBoundaryNames[bt]); 479*68717Seric return bt; 48067545Seric } 48168515Seric /* 48268515Seric ** MIME_GETCHAR -- get a character for MIME processing 48368515Seric ** 48468515Seric ** Treats boundaries as EOF. 48568515Seric ** 48668515Seric ** Parameters: 48768515Seric ** fp -- the input file. 48868517Seric ** boundaries -- the current MIME boundaries. 489*68717Seric ** btp -- if the return value is EOF, *btp is set to 490*68717Seric ** the type of the boundary. 49168515Seric ** 49268515Seric ** Returns: 49368515Seric ** The next character in the input stream. 49468515Seric */ 49567545Seric 49667545Seric int 497*68717Seric mime_getchar(fp, boundaries, btp) 49867545Seric register FILE *fp; 49968517Seric char **boundaries; 500*68717Seric int *btp; 50167545Seric { 50267545Seric int c; 50367545Seric static char *bp = NULL; 50467545Seric static int buflen = 0; 50567545Seric static bool atbol = TRUE; /* at beginning of line */ 506*68717Seric static int bt = MBT_SYNTAX; /* boundary type of next EOF */ 50767545Seric static char buf[128]; /* need not be a full line */ 50867545Seric 50967545Seric if (buflen > 0) 51067545Seric { 51167545Seric buflen--; 51267545Seric return *bp++; 51367545Seric } 51468515Seric bp = buf; 51568515Seric buflen = 0; 51667545Seric c = fgetc(fp); 51768515Seric if (c == '\n') 51868515Seric { 51968515Seric /* might be part of a MIME boundary */ 52068515Seric *bp++ = c; 52168515Seric atbol = TRUE; 52268515Seric c = fgetc(fp); 52368515Seric } 52468515Seric if (c != EOF) 52568515Seric *bp++ = c; 526*68717Seric else 527*68717Seric bt = MBT_FINAL; 52868517Seric if (atbol && c == '-') 52967545Seric { 53067545Seric /* check for a message boundary */ 53167545Seric c = fgetc(fp); 53267545Seric if (c != '-') 53367545Seric { 53467545Seric if (c != EOF) 53568515Seric *bp++ = c; 536*68717Seric else 537*68717Seric bt = MBT_FINAL; 53868515Seric buflen = bp - buf - 1; 53968515Seric bp = buf; 54068515Seric return *bp++; 54167545Seric } 54267545Seric 54367545Seric /* got "--", now check for rest of separator */ 54467545Seric *bp++ = '-'; 54567545Seric while (bp < &buf[sizeof buf - 1] && 54667545Seric (c = fgetc(fp)) != EOF && c != '\n') 54767545Seric { 54867545Seric *bp++ = c; 54967545Seric } 55067545Seric *bp = '\0'; 551*68717Seric bt = mimeboundary(&buf[1], boundaries); 552*68717Seric switch (bt) 55367545Seric { 55467545Seric case MBT_FINAL: 55567545Seric case MBT_INTERMED: 55667545Seric /* we have a message boundary */ 55767545Seric buflen = 0; 558*68717Seric *btp = bt; 55967545Seric return EOF; 56067545Seric } 56167545Seric 56267545Seric atbol = c == '\n'; 56367545Seric if (c != EOF) 56467545Seric *bp++ = c; 56567545Seric } 56667545Seric 56768515Seric buflen = bp - buf - 1; 56868515Seric if (buflen < 0) 569*68717Seric { 570*68717Seric *btp = bt; 57168515Seric return EOF; 572*68717Seric } 57368515Seric bp = buf; 57468515Seric return *bp++; 57567545Seric } 57667545Seric /* 57767545Seric ** MIMEBOUNDARY -- determine if this line is a MIME boundary & its type 57867545Seric ** 57967545Seric ** Parameters: 58067545Seric ** line -- the input line. 58168517Seric ** boundaries -- the set of currently pending boundaries. 58267545Seric ** 58367545Seric ** Returns: 58467545Seric ** MBT_NOTSEP -- if this is not a separator line 58567545Seric ** MBT_INTERMED -- if this is an intermediate separator 58667545Seric ** MBT_FINAL -- if this is a final boundary 58767545Seric ** MBT_SYNTAX -- if this is a boundary for the wrong 58867545Seric ** enclosure -- i.e., a syntax error. 58967545Seric */ 59067545Seric 59167545Seric int 59268517Seric mimeboundary(line, boundaries) 59367545Seric register char *line; 59468517Seric char **boundaries; 59567545Seric { 59667545Seric int type; 59767545Seric int i; 59868517Seric int savec; 59967545Seric 60068517Seric if (line[0] != '-' || line[1] != '-' || boundaries == NULL) 60167545Seric return MBT_NOTSEP; 60267545Seric i = strlen(line); 60367545Seric if (line[i - 1] == '\n') 60467545Seric i--; 605*68717Seric if (tTd(43, 5)) 606*68717Seric printf("mimeboundary: line=\"%.*s\"... ", i, line); 60768515Seric while (line[i - 1] == ' ' || line[i - 1] == '\t') 60868515Seric i--; 60967545Seric if (i > 2 && strncmp(&line[i - 2], "--", 2) == 0) 61067545Seric { 61167545Seric type = MBT_FINAL; 61267545Seric i -= 2; 61367545Seric } 61467545Seric else 61567545Seric type = MBT_INTERMED; 61667545Seric 61768517Seric savec = line[i]; 61868517Seric line[i] = '\0'; 61967545Seric /* XXX should check for improper nesting here */ 62068517Seric if (isboundary(&line[2], boundaries) < 0) 62167545Seric type = MBT_NOTSEP; 62268517Seric line[i] = savec; 62367545Seric if (tTd(43, 5)) 624*68717Seric printf("%s\n", MimeBoundaryNames[type]); 62567545Seric return type; 62667545Seric } 62767896Seric /* 62867896Seric ** DEFCHARSET -- return default character set for message 62967896Seric ** 63067896Seric ** The first choice for character set is for the mailer 63167896Seric ** corresponding to the envelope sender. If neither that 63267896Seric ** nor the global configuration file has a default character 63367896Seric ** set defined, return "unknown-8bit" as recommended by 63467896Seric ** RFC 1428 section 3. 63567896Seric ** 63667896Seric ** Parameters: 63767896Seric ** e -- the envelope for this message. 63867896Seric ** 63967896Seric ** Returns: 64067896Seric ** The default character set for that mailer. 64167896Seric */ 64267896Seric 64367896Seric char * 64467896Seric defcharset(e) 64567896Seric register ENVELOPE *e; 64667896Seric { 64767896Seric if (e != NULL && e->e_from.q_mailer != NULL && 64867896Seric e->e_from.q_mailer->m_defcharset != NULL) 64967896Seric return e->e_from.q_mailer->m_defcharset; 65067896Seric if (DefaultCharSet != NULL) 65167896Seric return DefaultCharSet; 65267896Seric return "unknown-8bit"; 65367896Seric } 65468517Seric /* 65568517Seric ** ISBOUNDARY -- is a given string a currently valid boundary? 65668517Seric ** 65768517Seric ** Parameters: 65868517Seric ** line -- the current input line. 65968517Seric ** boundaries -- the list of valid boundaries. 66068517Seric ** 66168517Seric ** Returns: 66268517Seric ** The index number in boundaries if the line is found. 66368517Seric ** -1 -- otherwise. 66468517Seric ** 66568517Seric */ 66668517Seric 66768517Seric int 66868517Seric isboundary(line, boundaries) 66968517Seric char *line; 67068517Seric char **boundaries; 67168517Seric { 67268517Seric register int i; 67368517Seric 67468711Seric for (i = 0; boundaries[i] != NULL; i++) 67568517Seric { 67668517Seric if (strcmp(line, boundaries[i]) == 0) 67768517Seric return i; 67868517Seric } 67968517Seric return -1; 68068517Seric } 681