1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright (c) 1998-2003 Sendmail, Inc. and its suppliers. 3*7c478bd9Sstevel@tonic-gate * All rights reserved. 4*7c478bd9Sstevel@tonic-gate * Copyright (c) 1994, 1996-1997 Eric P. Allman. All rights reserved. 5*7c478bd9Sstevel@tonic-gate * Copyright (c) 1994 6*7c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 7*7c478bd9Sstevel@tonic-gate * 8*7c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 9*7c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 10*7c478bd9Sstevel@tonic-gate * the sendmail distribution. 11*7c478bd9Sstevel@tonic-gate * 12*7c478bd9Sstevel@tonic-gate */ 13*7c478bd9Sstevel@tonic-gate 14*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 15*7c478bd9Sstevel@tonic-gate 16*7c478bd9Sstevel@tonic-gate #include <sendmail.h> 17*7c478bd9Sstevel@tonic-gate #include <string.h> 18*7c478bd9Sstevel@tonic-gate 19*7c478bd9Sstevel@tonic-gate SM_RCSID("@(#)$Id: mime.c,v 8.137 2004/09/02 21:37:26 ca Exp $") 20*7c478bd9Sstevel@tonic-gate 21*7c478bd9Sstevel@tonic-gate /* 22*7c478bd9Sstevel@tonic-gate ** MIME support. 23*7c478bd9Sstevel@tonic-gate ** 24*7c478bd9Sstevel@tonic-gate ** I am indebted to John Beck of Hewlett-Packard, who contributed 25*7c478bd9Sstevel@tonic-gate ** his code to me for inclusion. As it turns out, I did not use 26*7c478bd9Sstevel@tonic-gate ** his code since he used a "minimum change" approach that used 27*7c478bd9Sstevel@tonic-gate ** several temp files, and I wanted a "minimum impact" approach 28*7c478bd9Sstevel@tonic-gate ** that would avoid copying. However, looking over his code 29*7c478bd9Sstevel@tonic-gate ** helped me cement my understanding of the problem. 30*7c478bd9Sstevel@tonic-gate ** 31*7c478bd9Sstevel@tonic-gate ** I also looked at, but did not directly use, Nathaniel 32*7c478bd9Sstevel@tonic-gate ** Borenstein's "code.c" module. Again, it functioned as 33*7c478bd9Sstevel@tonic-gate ** a file-to-file translator, which did not fit within my 34*7c478bd9Sstevel@tonic-gate ** design bounds, but it was a useful base for understanding 35*7c478bd9Sstevel@tonic-gate ** the problem. 36*7c478bd9Sstevel@tonic-gate */ 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate /* use "old" mime 7 to 8 algorithm by default */ 39*7c478bd9Sstevel@tonic-gate #ifndef MIME7TO8_OLD 40*7c478bd9Sstevel@tonic-gate # define MIME7TO8_OLD 1 41*7c478bd9Sstevel@tonic-gate #endif /* ! MIME7TO8_OLD */ 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate #if MIME8TO7 44*7c478bd9Sstevel@tonic-gate static int isboundary __P((char *, char **)); 45*7c478bd9Sstevel@tonic-gate static int mimeboundary __P((char *, char **)); 46*7c478bd9Sstevel@tonic-gate static int mime_getchar __P((SM_FILE_T *, char **, int *)); 47*7c478bd9Sstevel@tonic-gate static int mime_getchar_crlf __P((SM_FILE_T *, char **, int *)); 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate /* character set for hex and base64 encoding */ 50*7c478bd9Sstevel@tonic-gate static char Base16Code[] = "0123456789ABCDEF"; 51*7c478bd9Sstevel@tonic-gate static char Base64Code[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate /* types of MIME boundaries */ 54*7c478bd9Sstevel@tonic-gate # define MBT_SYNTAX 0 /* syntax error */ 55*7c478bd9Sstevel@tonic-gate # define MBT_NOTSEP 1 /* not a boundary */ 56*7c478bd9Sstevel@tonic-gate # define MBT_INTERMED 2 /* intermediate boundary (no trailing --) */ 57*7c478bd9Sstevel@tonic-gate # define MBT_FINAL 3 /* final boundary (trailing -- included) */ 58*7c478bd9Sstevel@tonic-gate 59*7c478bd9Sstevel@tonic-gate static char *MimeBoundaryNames[] = 60*7c478bd9Sstevel@tonic-gate { 61*7c478bd9Sstevel@tonic-gate "SYNTAX", "NOTSEP", "INTERMED", "FINAL" 62*7c478bd9Sstevel@tonic-gate }; 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate static bool MapNLtoCRLF; 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate /* 67*7c478bd9Sstevel@tonic-gate ** MIME8TO7 -- output 8 bit body in 7 bit format 68*7c478bd9Sstevel@tonic-gate ** 69*7c478bd9Sstevel@tonic-gate ** The header has already been output -- this has to do the 70*7c478bd9Sstevel@tonic-gate ** 8 to 7 bit conversion. It would be easy if we didn't have 71*7c478bd9Sstevel@tonic-gate ** to deal with nested formats (multipart/xxx and message/rfc822). 72*7c478bd9Sstevel@tonic-gate ** 73*7c478bd9Sstevel@tonic-gate ** We won't be called if we don't have to do a conversion, and 74*7c478bd9Sstevel@tonic-gate ** appropriate MIME-Version: and Content-Type: fields have been 75*7c478bd9Sstevel@tonic-gate ** output. Any Content-Transfer-Encoding: field has not been 76*7c478bd9Sstevel@tonic-gate ** output, and we can add it here. 77*7c478bd9Sstevel@tonic-gate ** 78*7c478bd9Sstevel@tonic-gate ** Parameters: 79*7c478bd9Sstevel@tonic-gate ** mci -- mailer connection information. 80*7c478bd9Sstevel@tonic-gate ** header -- the header for this body part. 81*7c478bd9Sstevel@tonic-gate ** e -- envelope. 82*7c478bd9Sstevel@tonic-gate ** boundaries -- the currently pending message boundaries. 83*7c478bd9Sstevel@tonic-gate ** NULL if we are processing the outer portion. 84*7c478bd9Sstevel@tonic-gate ** flags -- to tweak processing. 85*7c478bd9Sstevel@tonic-gate ** 86*7c478bd9Sstevel@tonic-gate ** Returns: 87*7c478bd9Sstevel@tonic-gate ** An indicator of what terminated the message part: 88*7c478bd9Sstevel@tonic-gate ** MBT_FINAL -- the final boundary 89*7c478bd9Sstevel@tonic-gate ** MBT_INTERMED -- an intermediate boundary 90*7c478bd9Sstevel@tonic-gate ** MBT_NOTSEP -- an end of file 91*7c478bd9Sstevel@tonic-gate */ 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate struct args 94*7c478bd9Sstevel@tonic-gate { 95*7c478bd9Sstevel@tonic-gate char *a_field; /* name of field */ 96*7c478bd9Sstevel@tonic-gate char *a_value; /* value of that field */ 97*7c478bd9Sstevel@tonic-gate }; 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate int 100*7c478bd9Sstevel@tonic-gate mime8to7(mci, header, e, boundaries, flags) 101*7c478bd9Sstevel@tonic-gate register MCI *mci; 102*7c478bd9Sstevel@tonic-gate HDR *header; 103*7c478bd9Sstevel@tonic-gate register ENVELOPE *e; 104*7c478bd9Sstevel@tonic-gate char **boundaries; 105*7c478bd9Sstevel@tonic-gate int flags; 106*7c478bd9Sstevel@tonic-gate { 107*7c478bd9Sstevel@tonic-gate register char *p; 108*7c478bd9Sstevel@tonic-gate int linelen; 109*7c478bd9Sstevel@tonic-gate int bt; 110*7c478bd9Sstevel@tonic-gate off_t offset; 111*7c478bd9Sstevel@tonic-gate size_t sectionsize, sectionhighbits; 112*7c478bd9Sstevel@tonic-gate int i; 113*7c478bd9Sstevel@tonic-gate char *type; 114*7c478bd9Sstevel@tonic-gate char *subtype; 115*7c478bd9Sstevel@tonic-gate char *cte; 116*7c478bd9Sstevel@tonic-gate char **pvp; 117*7c478bd9Sstevel@tonic-gate int argc = 0; 118*7c478bd9Sstevel@tonic-gate char *bp; 119*7c478bd9Sstevel@tonic-gate bool use_qp = false; 120*7c478bd9Sstevel@tonic-gate struct args argv[MAXMIMEARGS]; 121*7c478bd9Sstevel@tonic-gate char bbuf[128]; 122*7c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 123*7c478bd9Sstevel@tonic-gate char pvpbuf[MAXLINE]; 124*7c478bd9Sstevel@tonic-gate extern unsigned char MimeTokenTab[256]; 125*7c478bd9Sstevel@tonic-gate 126*7c478bd9Sstevel@tonic-gate if (tTd(43, 1)) 127*7c478bd9Sstevel@tonic-gate { 128*7c478bd9Sstevel@tonic-gate sm_dprintf("mime8to7: flags = %x, boundaries =", flags); 129*7c478bd9Sstevel@tonic-gate if (boundaries[0] == NULL) 130*7c478bd9Sstevel@tonic-gate sm_dprintf(" <none>"); 131*7c478bd9Sstevel@tonic-gate else 132*7c478bd9Sstevel@tonic-gate { 133*7c478bd9Sstevel@tonic-gate for (i = 0; boundaries[i] != NULL; i++) 134*7c478bd9Sstevel@tonic-gate sm_dprintf(" %s", boundaries[i]); 135*7c478bd9Sstevel@tonic-gate } 136*7c478bd9Sstevel@tonic-gate sm_dprintf("\n"); 137*7c478bd9Sstevel@tonic-gate } 138*7c478bd9Sstevel@tonic-gate MapNLtoCRLF = true; 139*7c478bd9Sstevel@tonic-gate p = hvalue("Content-Transfer-Encoding", header); 140*7c478bd9Sstevel@tonic-gate if (p == NULL || 141*7c478bd9Sstevel@tonic-gate (pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL, 142*7c478bd9Sstevel@tonic-gate MimeTokenTab, false)) == NULL || 143*7c478bd9Sstevel@tonic-gate pvp[0] == NULL) 144*7c478bd9Sstevel@tonic-gate { 145*7c478bd9Sstevel@tonic-gate cte = NULL; 146*7c478bd9Sstevel@tonic-gate } 147*7c478bd9Sstevel@tonic-gate else 148*7c478bd9Sstevel@tonic-gate { 149*7c478bd9Sstevel@tonic-gate cataddr(pvp, NULL, buf, sizeof buf, '\0'); 150*7c478bd9Sstevel@tonic-gate cte = sm_rpool_strdup_x(e->e_rpool, buf); 151*7c478bd9Sstevel@tonic-gate } 152*7c478bd9Sstevel@tonic-gate 153*7c478bd9Sstevel@tonic-gate type = subtype = NULL; 154*7c478bd9Sstevel@tonic-gate p = hvalue("Content-Type", header); 155*7c478bd9Sstevel@tonic-gate if (p == NULL) 156*7c478bd9Sstevel@tonic-gate { 157*7c478bd9Sstevel@tonic-gate if (bitset(M87F_DIGEST, flags)) 158*7c478bd9Sstevel@tonic-gate p = "message/rfc822"; 159*7c478bd9Sstevel@tonic-gate else 160*7c478bd9Sstevel@tonic-gate p = "text/plain"; 161*7c478bd9Sstevel@tonic-gate } 162*7c478bd9Sstevel@tonic-gate if (p != NULL && 163*7c478bd9Sstevel@tonic-gate (pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL, 164*7c478bd9Sstevel@tonic-gate MimeTokenTab, false)) != NULL && 165*7c478bd9Sstevel@tonic-gate pvp[0] != NULL) 166*7c478bd9Sstevel@tonic-gate { 167*7c478bd9Sstevel@tonic-gate if (tTd(43, 40)) 168*7c478bd9Sstevel@tonic-gate { 169*7c478bd9Sstevel@tonic-gate for (i = 0; pvp[i] != NULL; i++) 170*7c478bd9Sstevel@tonic-gate sm_dprintf("pvp[%d] = \"%s\"\n", i, pvp[i]); 171*7c478bd9Sstevel@tonic-gate } 172*7c478bd9Sstevel@tonic-gate type = *pvp++; 173*7c478bd9Sstevel@tonic-gate if (*pvp != NULL && strcmp(*pvp, "/") == 0 && 174*7c478bd9Sstevel@tonic-gate *++pvp != NULL) 175*7c478bd9Sstevel@tonic-gate { 176*7c478bd9Sstevel@tonic-gate subtype = *pvp++; 177*7c478bd9Sstevel@tonic-gate } 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate /* break out parameters */ 180*7c478bd9Sstevel@tonic-gate while (*pvp != NULL && argc < MAXMIMEARGS) 181*7c478bd9Sstevel@tonic-gate { 182*7c478bd9Sstevel@tonic-gate /* skip to semicolon separator */ 183*7c478bd9Sstevel@tonic-gate while (*pvp != NULL && strcmp(*pvp, ";") != 0) 184*7c478bd9Sstevel@tonic-gate pvp++; 185*7c478bd9Sstevel@tonic-gate if (*pvp++ == NULL || *pvp == NULL) 186*7c478bd9Sstevel@tonic-gate break; 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate /* complain about empty values */ 189*7c478bd9Sstevel@tonic-gate if (strcmp(*pvp, ";") == 0) 190*7c478bd9Sstevel@tonic-gate { 191*7c478bd9Sstevel@tonic-gate usrerr("mime8to7: Empty parameter in Content-Type header"); 192*7c478bd9Sstevel@tonic-gate 193*7c478bd9Sstevel@tonic-gate /* avoid bounce loops */ 194*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_DONT_MIME; 195*7c478bd9Sstevel@tonic-gate continue; 196*7c478bd9Sstevel@tonic-gate } 197*7c478bd9Sstevel@tonic-gate 198*7c478bd9Sstevel@tonic-gate /* extract field name */ 199*7c478bd9Sstevel@tonic-gate argv[argc].a_field = *pvp++; 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate /* see if there is a value */ 202*7c478bd9Sstevel@tonic-gate if (*pvp != NULL && strcmp(*pvp, "=") == 0 && 203*7c478bd9Sstevel@tonic-gate (*++pvp == NULL || strcmp(*pvp, ";") != 0)) 204*7c478bd9Sstevel@tonic-gate { 205*7c478bd9Sstevel@tonic-gate argv[argc].a_value = *pvp; 206*7c478bd9Sstevel@tonic-gate argc++; 207*7c478bd9Sstevel@tonic-gate } 208*7c478bd9Sstevel@tonic-gate } 209*7c478bd9Sstevel@tonic-gate } 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate /* check for disaster cases */ 212*7c478bd9Sstevel@tonic-gate if (type == NULL) 213*7c478bd9Sstevel@tonic-gate type = "-none-"; 214*7c478bd9Sstevel@tonic-gate if (subtype == NULL) 215*7c478bd9Sstevel@tonic-gate subtype = "-none-"; 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate /* don't propogate some flags more than one level into the message */ 218*7c478bd9Sstevel@tonic-gate flags &= ~M87F_DIGEST; 219*7c478bd9Sstevel@tonic-gate 220*7c478bd9Sstevel@tonic-gate /* 221*7c478bd9Sstevel@tonic-gate ** Check for cases that can not be encoded. 222*7c478bd9Sstevel@tonic-gate ** 223*7c478bd9Sstevel@tonic-gate ** For example, you can't encode certain kinds of types 224*7c478bd9Sstevel@tonic-gate ** or already-encoded messages. If we find this case, 225*7c478bd9Sstevel@tonic-gate ** just copy it through. 226*7c478bd9Sstevel@tonic-gate */ 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "%.100s/%.100s", type, subtype); 229*7c478bd9Sstevel@tonic-gate if (wordinclass(buf, 'n') || (cte != NULL && !wordinclass(cte, 'e'))) 230*7c478bd9Sstevel@tonic-gate flags |= M87F_NO8BIT; 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate # ifdef USE_B_CLASS 233*7c478bd9Sstevel@tonic-gate if (wordinclass(buf, 'b') || wordinclass(type, 'b')) 234*7c478bd9Sstevel@tonic-gate MapNLtoCRLF = false; 235*7c478bd9Sstevel@tonic-gate # endif /* USE_B_CLASS */ 236*7c478bd9Sstevel@tonic-gate if (wordinclass(buf, 'q') || wordinclass(type, 'q')) 237*7c478bd9Sstevel@tonic-gate use_qp = true; 238*7c478bd9Sstevel@tonic-gate 239*7c478bd9Sstevel@tonic-gate /* 240*7c478bd9Sstevel@tonic-gate ** Multipart requires special processing. 241*7c478bd9Sstevel@tonic-gate ** 242*7c478bd9Sstevel@tonic-gate ** Do a recursive descent into the message. 243*7c478bd9Sstevel@tonic-gate */ 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate if (sm_strcasecmp(type, "multipart") == 0 && 246*7c478bd9Sstevel@tonic-gate (!bitset(M87F_NO8BIT, flags) || bitset(M87F_NO8TO7, flags))) 247*7c478bd9Sstevel@tonic-gate { 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate if (sm_strcasecmp(subtype, "digest") == 0) 250*7c478bd9Sstevel@tonic-gate flags |= M87F_DIGEST; 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate for (i = 0; i < argc; i++) 253*7c478bd9Sstevel@tonic-gate { 254*7c478bd9Sstevel@tonic-gate if (sm_strcasecmp(argv[i].a_field, "boundary") == 0) 255*7c478bd9Sstevel@tonic-gate break; 256*7c478bd9Sstevel@tonic-gate } 257*7c478bd9Sstevel@tonic-gate if (i >= argc || argv[i].a_value == NULL) 258*7c478bd9Sstevel@tonic-gate { 259*7c478bd9Sstevel@tonic-gate usrerr("mime8to7: Content-Type: \"%s\": %s boundary", 260*7c478bd9Sstevel@tonic-gate i >= argc ? "missing" : "bogus", p); 261*7c478bd9Sstevel@tonic-gate p = "---"; 262*7c478bd9Sstevel@tonic-gate 263*7c478bd9Sstevel@tonic-gate /* avoid bounce loops */ 264*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_DONT_MIME; 265*7c478bd9Sstevel@tonic-gate } 266*7c478bd9Sstevel@tonic-gate else 267*7c478bd9Sstevel@tonic-gate { 268*7c478bd9Sstevel@tonic-gate p = argv[i].a_value; 269*7c478bd9Sstevel@tonic-gate stripquotes(p); 270*7c478bd9Sstevel@tonic-gate } 271*7c478bd9Sstevel@tonic-gate if (sm_strlcpy(bbuf, p, sizeof bbuf) >= sizeof bbuf) 272*7c478bd9Sstevel@tonic-gate { 273*7c478bd9Sstevel@tonic-gate usrerr("mime8to7: multipart boundary \"%s\" too long", 274*7c478bd9Sstevel@tonic-gate p); 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate /* avoid bounce loops */ 277*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_DONT_MIME; 278*7c478bd9Sstevel@tonic-gate } 279*7c478bd9Sstevel@tonic-gate 280*7c478bd9Sstevel@tonic-gate if (tTd(43, 1)) 281*7c478bd9Sstevel@tonic-gate sm_dprintf("mime8to7: multipart boundary \"%s\"\n", 282*7c478bd9Sstevel@tonic-gate bbuf); 283*7c478bd9Sstevel@tonic-gate for (i = 0; i < MAXMIMENESTING; i++) 284*7c478bd9Sstevel@tonic-gate { 285*7c478bd9Sstevel@tonic-gate if (boundaries[i] == NULL) 286*7c478bd9Sstevel@tonic-gate break; 287*7c478bd9Sstevel@tonic-gate } 288*7c478bd9Sstevel@tonic-gate if (i >= MAXMIMENESTING) 289*7c478bd9Sstevel@tonic-gate { 290*7c478bd9Sstevel@tonic-gate usrerr("mime8to7: multipart nesting boundary too deep"); 291*7c478bd9Sstevel@tonic-gate 292*7c478bd9Sstevel@tonic-gate /* avoid bounce loops */ 293*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_DONT_MIME; 294*7c478bd9Sstevel@tonic-gate } 295*7c478bd9Sstevel@tonic-gate else 296*7c478bd9Sstevel@tonic-gate { 297*7c478bd9Sstevel@tonic-gate boundaries[i] = bbuf; 298*7c478bd9Sstevel@tonic-gate boundaries[i + 1] = NULL; 299*7c478bd9Sstevel@tonic-gate } 300*7c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_INMIME; 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate /* skip the early "comment" prologue */ 303*7c478bd9Sstevel@tonic-gate putline("", mci); 304*7c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_INHEADER; 305*7c478bd9Sstevel@tonic-gate bt = MBT_FINAL; 306*7c478bd9Sstevel@tonic-gate while (sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, sizeof buf) 307*7c478bd9Sstevel@tonic-gate != NULL) 308*7c478bd9Sstevel@tonic-gate { 309*7c478bd9Sstevel@tonic-gate bt = mimeboundary(buf, boundaries); 310*7c478bd9Sstevel@tonic-gate if (bt != MBT_NOTSEP) 311*7c478bd9Sstevel@tonic-gate break; 312*7c478bd9Sstevel@tonic-gate putxline(buf, strlen(buf), mci, 313*7c478bd9Sstevel@tonic-gate PXLF_MAPFROM|PXLF_STRIP8BIT); 314*7c478bd9Sstevel@tonic-gate if (tTd(43, 99)) 315*7c478bd9Sstevel@tonic-gate sm_dprintf(" ...%s", buf); 316*7c478bd9Sstevel@tonic-gate } 317*7c478bd9Sstevel@tonic-gate if (sm_io_eof(e->e_dfp)) 318*7c478bd9Sstevel@tonic-gate bt = MBT_FINAL; 319*7c478bd9Sstevel@tonic-gate while (bt != MBT_FINAL) 320*7c478bd9Sstevel@tonic-gate { 321*7c478bd9Sstevel@tonic-gate auto HDR *hdr = NULL; 322*7c478bd9Sstevel@tonic-gate 323*7c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(buf, sizeof buf, 2, "--", bbuf); 324*7c478bd9Sstevel@tonic-gate putline(buf, mci); 325*7c478bd9Sstevel@tonic-gate if (tTd(43, 35)) 326*7c478bd9Sstevel@tonic-gate sm_dprintf(" ...%s\n", buf); 327*7c478bd9Sstevel@tonic-gate collect(e->e_dfp, false, &hdr, e, false); 328*7c478bd9Sstevel@tonic-gate if (tTd(43, 101)) 329*7c478bd9Sstevel@tonic-gate putline("+++after collect", mci); 330*7c478bd9Sstevel@tonic-gate putheader(mci, hdr, e, flags); 331*7c478bd9Sstevel@tonic-gate if (tTd(43, 101)) 332*7c478bd9Sstevel@tonic-gate putline("+++after putheader", mci); 333*7c478bd9Sstevel@tonic-gate bt = mime8to7(mci, hdr, e, boundaries, flags); 334*7c478bd9Sstevel@tonic-gate } 335*7c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(buf, sizeof buf, 3, "--", bbuf, "--"); 336*7c478bd9Sstevel@tonic-gate putline(buf, mci); 337*7c478bd9Sstevel@tonic-gate if (tTd(43, 35)) 338*7c478bd9Sstevel@tonic-gate sm_dprintf(" ...%s\n", buf); 339*7c478bd9Sstevel@tonic-gate boundaries[i] = NULL; 340*7c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_INMIME; 341*7c478bd9Sstevel@tonic-gate 342*7c478bd9Sstevel@tonic-gate /* skip the late "comment" epilogue */ 343*7c478bd9Sstevel@tonic-gate while (sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, sizeof buf) 344*7c478bd9Sstevel@tonic-gate != NULL) 345*7c478bd9Sstevel@tonic-gate { 346*7c478bd9Sstevel@tonic-gate bt = mimeboundary(buf, boundaries); 347*7c478bd9Sstevel@tonic-gate if (bt != MBT_NOTSEP) 348*7c478bd9Sstevel@tonic-gate break; 349*7c478bd9Sstevel@tonic-gate putxline(buf, strlen(buf), mci, 350*7c478bd9Sstevel@tonic-gate PXLF_MAPFROM|PXLF_STRIP8BIT); 351*7c478bd9Sstevel@tonic-gate if (tTd(43, 99)) 352*7c478bd9Sstevel@tonic-gate sm_dprintf(" ...%s", buf); 353*7c478bd9Sstevel@tonic-gate } 354*7c478bd9Sstevel@tonic-gate if (sm_io_eof(e->e_dfp)) 355*7c478bd9Sstevel@tonic-gate bt = MBT_FINAL; 356*7c478bd9Sstevel@tonic-gate if (tTd(43, 3)) 357*7c478bd9Sstevel@tonic-gate sm_dprintf("\t\t\tmime8to7=>%s (multipart)\n", 358*7c478bd9Sstevel@tonic-gate MimeBoundaryNames[bt]); 359*7c478bd9Sstevel@tonic-gate return bt; 360*7c478bd9Sstevel@tonic-gate } 361*7c478bd9Sstevel@tonic-gate 362*7c478bd9Sstevel@tonic-gate /* 363*7c478bd9Sstevel@tonic-gate ** Message/xxx types -- recurse exactly once. 364*7c478bd9Sstevel@tonic-gate ** 365*7c478bd9Sstevel@tonic-gate ** Class 's' is predefined to have "rfc822" only. 366*7c478bd9Sstevel@tonic-gate */ 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate if (sm_strcasecmp(type, "message") == 0) 369*7c478bd9Sstevel@tonic-gate { 370*7c478bd9Sstevel@tonic-gate if (!wordinclass(subtype, 's')) 371*7c478bd9Sstevel@tonic-gate { 372*7c478bd9Sstevel@tonic-gate flags |= M87F_NO8BIT; 373*7c478bd9Sstevel@tonic-gate } 374*7c478bd9Sstevel@tonic-gate else 375*7c478bd9Sstevel@tonic-gate { 376*7c478bd9Sstevel@tonic-gate auto HDR *hdr = NULL; 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate putline("", mci); 379*7c478bd9Sstevel@tonic-gate 380*7c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_INMIME; 381*7c478bd9Sstevel@tonic-gate collect(e->e_dfp, false, &hdr, e, false); 382*7c478bd9Sstevel@tonic-gate if (tTd(43, 101)) 383*7c478bd9Sstevel@tonic-gate putline("+++after collect", mci); 384*7c478bd9Sstevel@tonic-gate putheader(mci, hdr, e, flags); 385*7c478bd9Sstevel@tonic-gate if (tTd(43, 101)) 386*7c478bd9Sstevel@tonic-gate putline("+++after putheader", mci); 387*7c478bd9Sstevel@tonic-gate if (hvalue("MIME-Version", hdr) == NULL && 388*7c478bd9Sstevel@tonic-gate !bitset(M87F_NO8TO7, flags)) 389*7c478bd9Sstevel@tonic-gate putline("MIME-Version: 1.0", mci); 390*7c478bd9Sstevel@tonic-gate bt = mime8to7(mci, hdr, e, boundaries, flags); 391*7c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_INMIME; 392*7c478bd9Sstevel@tonic-gate return bt; 393*7c478bd9Sstevel@tonic-gate } 394*7c478bd9Sstevel@tonic-gate } 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate /* 397*7c478bd9Sstevel@tonic-gate ** Non-compound body type 398*7c478bd9Sstevel@tonic-gate ** 399*7c478bd9Sstevel@tonic-gate ** Compute the ratio of seven to eight bit characters; 400*7c478bd9Sstevel@tonic-gate ** use that as a heuristic to decide how to do the 401*7c478bd9Sstevel@tonic-gate ** encoding. 402*7c478bd9Sstevel@tonic-gate */ 403*7c478bd9Sstevel@tonic-gate 404*7c478bd9Sstevel@tonic-gate sectionsize = sectionhighbits = 0; 405*7c478bd9Sstevel@tonic-gate if (!bitset(M87F_NO8BIT|M87F_NO8TO7, flags)) 406*7c478bd9Sstevel@tonic-gate { 407*7c478bd9Sstevel@tonic-gate /* remember where we were */ 408*7c478bd9Sstevel@tonic-gate offset = sm_io_tell(e->e_dfp, SM_TIME_DEFAULT); 409*7c478bd9Sstevel@tonic-gate if (offset == -1) 410*7c478bd9Sstevel@tonic-gate syserr("mime8to7: cannot sm_io_tell on %cf%s", 411*7c478bd9Sstevel@tonic-gate DATAFL_LETTER, e->e_id); 412*7c478bd9Sstevel@tonic-gate 413*7c478bd9Sstevel@tonic-gate /* do a scan of this body type to count character types */ 414*7c478bd9Sstevel@tonic-gate while (sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, sizeof buf) 415*7c478bd9Sstevel@tonic-gate != NULL) 416*7c478bd9Sstevel@tonic-gate { 417*7c478bd9Sstevel@tonic-gate if (mimeboundary(buf, boundaries) != MBT_NOTSEP) 418*7c478bd9Sstevel@tonic-gate break; 419*7c478bd9Sstevel@tonic-gate for (p = buf; *p != '\0'; p++) 420*7c478bd9Sstevel@tonic-gate { 421*7c478bd9Sstevel@tonic-gate /* count bytes with the high bit set */ 422*7c478bd9Sstevel@tonic-gate sectionsize++; 423*7c478bd9Sstevel@tonic-gate if (bitset(0200, *p)) 424*7c478bd9Sstevel@tonic-gate sectionhighbits++; 425*7c478bd9Sstevel@tonic-gate } 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate /* 428*7c478bd9Sstevel@tonic-gate ** Heuristic: if 1/4 of the first 4K bytes are 8-bit, 429*7c478bd9Sstevel@tonic-gate ** assume base64. This heuristic avoids double-reading 430*7c478bd9Sstevel@tonic-gate ** large graphics or video files. 431*7c478bd9Sstevel@tonic-gate */ 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate if (sectionsize >= 4096 && 434*7c478bd9Sstevel@tonic-gate sectionhighbits > sectionsize / 4) 435*7c478bd9Sstevel@tonic-gate break; 436*7c478bd9Sstevel@tonic-gate } 437*7c478bd9Sstevel@tonic-gate 438*7c478bd9Sstevel@tonic-gate /* return to the original offset for processing */ 439*7c478bd9Sstevel@tonic-gate /* XXX use relative seeks to handle >31 bit file sizes? */ 440*7c478bd9Sstevel@tonic-gate if (sm_io_seek(e->e_dfp, SM_TIME_DEFAULT, offset, SEEK_SET) < 0) 441*7c478bd9Sstevel@tonic-gate syserr("mime8to7: cannot sm_io_fseek on %cf%s", 442*7c478bd9Sstevel@tonic-gate DATAFL_LETTER, e->e_id); 443*7c478bd9Sstevel@tonic-gate else 444*7c478bd9Sstevel@tonic-gate sm_io_clearerr(e->e_dfp); 445*7c478bd9Sstevel@tonic-gate } 446*7c478bd9Sstevel@tonic-gate 447*7c478bd9Sstevel@tonic-gate /* 448*7c478bd9Sstevel@tonic-gate ** Heuristically determine encoding method. 449*7c478bd9Sstevel@tonic-gate ** If more than 1/8 of the total characters have the 450*7c478bd9Sstevel@tonic-gate ** eighth bit set, use base64; else use quoted-printable. 451*7c478bd9Sstevel@tonic-gate ** However, only encode binary encoded data as base64, 452*7c478bd9Sstevel@tonic-gate ** since otherwise the NL=>CRLF mapping will be a problem. 453*7c478bd9Sstevel@tonic-gate */ 454*7c478bd9Sstevel@tonic-gate 455*7c478bd9Sstevel@tonic-gate if (tTd(43, 8)) 456*7c478bd9Sstevel@tonic-gate { 457*7c478bd9Sstevel@tonic-gate sm_dprintf("mime8to7: %ld high bit(s) in %ld byte(s), cte=%s, type=%s/%s\n", 458*7c478bd9Sstevel@tonic-gate (long) sectionhighbits, (long) sectionsize, 459*7c478bd9Sstevel@tonic-gate cte == NULL ? "[none]" : cte, 460*7c478bd9Sstevel@tonic-gate type == NULL ? "[none]" : type, 461*7c478bd9Sstevel@tonic-gate subtype == NULL ? "[none]" : subtype); 462*7c478bd9Sstevel@tonic-gate } 463*7c478bd9Sstevel@tonic-gate if (cte != NULL && sm_strcasecmp(cte, "binary") == 0) 464*7c478bd9Sstevel@tonic-gate sectionsize = sectionhighbits; 465*7c478bd9Sstevel@tonic-gate linelen = 0; 466*7c478bd9Sstevel@tonic-gate bp = buf; 467*7c478bd9Sstevel@tonic-gate if (sectionhighbits == 0) 468*7c478bd9Sstevel@tonic-gate { 469*7c478bd9Sstevel@tonic-gate /* no encoding necessary */ 470*7c478bd9Sstevel@tonic-gate if (cte != NULL && 471*7c478bd9Sstevel@tonic-gate bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, 472*7c478bd9Sstevel@tonic-gate mci->mci_flags) && 473*7c478bd9Sstevel@tonic-gate !bitset(M87F_NO8TO7, flags)) 474*7c478bd9Sstevel@tonic-gate { 475*7c478bd9Sstevel@tonic-gate /* 476*7c478bd9Sstevel@tonic-gate ** Skip _unless_ in MIME mode and potentially 477*7c478bd9Sstevel@tonic-gate ** converting from 8 bit to 7 bit MIME. See 478*7c478bd9Sstevel@tonic-gate ** putheader() for the counterpart where the 479*7c478bd9Sstevel@tonic-gate ** CTE header is skipped in the opposite 480*7c478bd9Sstevel@tonic-gate ** situation. 481*7c478bd9Sstevel@tonic-gate */ 482*7c478bd9Sstevel@tonic-gate 483*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, 484*7c478bd9Sstevel@tonic-gate "Content-Transfer-Encoding: %.200s", cte); 485*7c478bd9Sstevel@tonic-gate putline(buf, mci); 486*7c478bd9Sstevel@tonic-gate if (tTd(43, 36)) 487*7c478bd9Sstevel@tonic-gate sm_dprintf(" ...%s\n", buf); 488*7c478bd9Sstevel@tonic-gate } 489*7c478bd9Sstevel@tonic-gate putline("", mci); 490*7c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_INHEADER; 491*7c478bd9Sstevel@tonic-gate while (sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, sizeof buf) 492*7c478bd9Sstevel@tonic-gate != NULL) 493*7c478bd9Sstevel@tonic-gate { 494*7c478bd9Sstevel@tonic-gate bt = mimeboundary(buf, boundaries); 495*7c478bd9Sstevel@tonic-gate if (bt != MBT_NOTSEP) 496*7c478bd9Sstevel@tonic-gate break; 497*7c478bd9Sstevel@tonic-gate putline(buf, mci); 498*7c478bd9Sstevel@tonic-gate } 499*7c478bd9Sstevel@tonic-gate if (sm_io_eof(e->e_dfp)) 500*7c478bd9Sstevel@tonic-gate bt = MBT_FINAL; 501*7c478bd9Sstevel@tonic-gate } 502*7c478bd9Sstevel@tonic-gate else if (!MapNLtoCRLF || 503*7c478bd9Sstevel@tonic-gate (sectionsize / 8 < sectionhighbits && !use_qp)) 504*7c478bd9Sstevel@tonic-gate { 505*7c478bd9Sstevel@tonic-gate /* use base64 encoding */ 506*7c478bd9Sstevel@tonic-gate int c1, c2; 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate if (tTd(43, 36)) 509*7c478bd9Sstevel@tonic-gate sm_dprintf(" ...Content-Transfer-Encoding: base64\n"); 510*7c478bd9Sstevel@tonic-gate putline("Content-Transfer-Encoding: base64", mci); 511*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, 512*7c478bd9Sstevel@tonic-gate "X-MIME-Autoconverted: from 8bit to base64 by %s id %s", 513*7c478bd9Sstevel@tonic-gate MyHostName, e->e_id); 514*7c478bd9Sstevel@tonic-gate putline(buf, mci); 515*7c478bd9Sstevel@tonic-gate putline("", mci); 516*7c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_INHEADER; 517*7c478bd9Sstevel@tonic-gate while ((c1 = mime_getchar_crlf(e->e_dfp, boundaries, &bt)) != 518*7c478bd9Sstevel@tonic-gate SM_IO_EOF) 519*7c478bd9Sstevel@tonic-gate { 520*7c478bd9Sstevel@tonic-gate if (linelen > 71) 521*7c478bd9Sstevel@tonic-gate { 522*7c478bd9Sstevel@tonic-gate *bp = '\0'; 523*7c478bd9Sstevel@tonic-gate putline(buf, mci); 524*7c478bd9Sstevel@tonic-gate linelen = 0; 525*7c478bd9Sstevel@tonic-gate bp = buf; 526*7c478bd9Sstevel@tonic-gate } 527*7c478bd9Sstevel@tonic-gate linelen += 4; 528*7c478bd9Sstevel@tonic-gate *bp++ = Base64Code[(c1 >> 2)]; 529*7c478bd9Sstevel@tonic-gate c1 = (c1 & 0x03) << 4; 530*7c478bd9Sstevel@tonic-gate c2 = mime_getchar_crlf(e->e_dfp, boundaries, &bt); 531*7c478bd9Sstevel@tonic-gate if (c2 == SM_IO_EOF) 532*7c478bd9Sstevel@tonic-gate { 533*7c478bd9Sstevel@tonic-gate *bp++ = Base64Code[c1]; 534*7c478bd9Sstevel@tonic-gate *bp++ = '='; 535*7c478bd9Sstevel@tonic-gate *bp++ = '='; 536*7c478bd9Sstevel@tonic-gate break; 537*7c478bd9Sstevel@tonic-gate } 538*7c478bd9Sstevel@tonic-gate c1 |= (c2 >> 4) & 0x0f; 539*7c478bd9Sstevel@tonic-gate *bp++ = Base64Code[c1]; 540*7c478bd9Sstevel@tonic-gate c1 = (c2 & 0x0f) << 2; 541*7c478bd9Sstevel@tonic-gate c2 = mime_getchar_crlf(e->e_dfp, boundaries, &bt); 542*7c478bd9Sstevel@tonic-gate if (c2 == SM_IO_EOF) 543*7c478bd9Sstevel@tonic-gate { 544*7c478bd9Sstevel@tonic-gate *bp++ = Base64Code[c1]; 545*7c478bd9Sstevel@tonic-gate *bp++ = '='; 546*7c478bd9Sstevel@tonic-gate break; 547*7c478bd9Sstevel@tonic-gate } 548*7c478bd9Sstevel@tonic-gate c1 |= (c2 >> 6) & 0x03; 549*7c478bd9Sstevel@tonic-gate *bp++ = Base64Code[c1]; 550*7c478bd9Sstevel@tonic-gate *bp++ = Base64Code[c2 & 0x3f]; 551*7c478bd9Sstevel@tonic-gate } 552*7c478bd9Sstevel@tonic-gate *bp = '\0'; 553*7c478bd9Sstevel@tonic-gate putline(buf, mci); 554*7c478bd9Sstevel@tonic-gate } 555*7c478bd9Sstevel@tonic-gate else 556*7c478bd9Sstevel@tonic-gate { 557*7c478bd9Sstevel@tonic-gate /* use quoted-printable encoding */ 558*7c478bd9Sstevel@tonic-gate int c1, c2; 559*7c478bd9Sstevel@tonic-gate int fromstate; 560*7c478bd9Sstevel@tonic-gate BITMAP256 badchars; 561*7c478bd9Sstevel@tonic-gate 562*7c478bd9Sstevel@tonic-gate /* set up map of characters that must be mapped */ 563*7c478bd9Sstevel@tonic-gate clrbitmap(badchars); 564*7c478bd9Sstevel@tonic-gate for (c1 = 0x00; c1 < 0x20; c1++) 565*7c478bd9Sstevel@tonic-gate setbitn(c1, badchars); 566*7c478bd9Sstevel@tonic-gate clrbitn('\t', badchars); 567*7c478bd9Sstevel@tonic-gate for (c1 = 0x7f; c1 < 0x100; c1++) 568*7c478bd9Sstevel@tonic-gate setbitn(c1, badchars); 569*7c478bd9Sstevel@tonic-gate setbitn('=', badchars); 570*7c478bd9Sstevel@tonic-gate if (bitnset(M_EBCDIC, mci->mci_mailer->m_flags)) 571*7c478bd9Sstevel@tonic-gate for (p = "!\"#$@[\\]^`{|}~"; *p != '\0'; p++) 572*7c478bd9Sstevel@tonic-gate setbitn(*p, badchars); 573*7c478bd9Sstevel@tonic-gate 574*7c478bd9Sstevel@tonic-gate if (tTd(43, 36)) 575*7c478bd9Sstevel@tonic-gate sm_dprintf(" ...Content-Transfer-Encoding: quoted-printable\n"); 576*7c478bd9Sstevel@tonic-gate putline("Content-Transfer-Encoding: quoted-printable", mci); 577*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, 578*7c478bd9Sstevel@tonic-gate "X-MIME-Autoconverted: from 8bit to quoted-printable by %s id %s", 579*7c478bd9Sstevel@tonic-gate MyHostName, e->e_id); 580*7c478bd9Sstevel@tonic-gate putline(buf, mci); 581*7c478bd9Sstevel@tonic-gate putline("", mci); 582*7c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_INHEADER; 583*7c478bd9Sstevel@tonic-gate fromstate = 0; 584*7c478bd9Sstevel@tonic-gate c2 = '\n'; 585*7c478bd9Sstevel@tonic-gate while ((c1 = mime_getchar(e->e_dfp, boundaries, &bt)) != 586*7c478bd9Sstevel@tonic-gate SM_IO_EOF) 587*7c478bd9Sstevel@tonic-gate { 588*7c478bd9Sstevel@tonic-gate if (c1 == '\n') 589*7c478bd9Sstevel@tonic-gate { 590*7c478bd9Sstevel@tonic-gate if (c2 == ' ' || c2 == '\t') 591*7c478bd9Sstevel@tonic-gate { 592*7c478bd9Sstevel@tonic-gate *bp++ = '='; 593*7c478bd9Sstevel@tonic-gate *bp++ = Base16Code[(c2 >> 4) & 0x0f]; 594*7c478bd9Sstevel@tonic-gate *bp++ = Base16Code[c2 & 0x0f]; 595*7c478bd9Sstevel@tonic-gate } 596*7c478bd9Sstevel@tonic-gate if (buf[0] == '.' && bp == &buf[1]) 597*7c478bd9Sstevel@tonic-gate { 598*7c478bd9Sstevel@tonic-gate buf[0] = '='; 599*7c478bd9Sstevel@tonic-gate *bp++ = Base16Code[('.' >> 4) & 0x0f]; 600*7c478bd9Sstevel@tonic-gate *bp++ = Base16Code['.' & 0x0f]; 601*7c478bd9Sstevel@tonic-gate } 602*7c478bd9Sstevel@tonic-gate *bp = '\0'; 603*7c478bd9Sstevel@tonic-gate putline(buf, mci); 604*7c478bd9Sstevel@tonic-gate linelen = fromstate = 0; 605*7c478bd9Sstevel@tonic-gate bp = buf; 606*7c478bd9Sstevel@tonic-gate c2 = c1; 607*7c478bd9Sstevel@tonic-gate continue; 608*7c478bd9Sstevel@tonic-gate } 609*7c478bd9Sstevel@tonic-gate if (c2 == ' ' && linelen == 4 && fromstate == 4 && 610*7c478bd9Sstevel@tonic-gate bitnset(M_ESCFROM, mci->mci_mailer->m_flags)) 611*7c478bd9Sstevel@tonic-gate { 612*7c478bd9Sstevel@tonic-gate *bp++ = '='; 613*7c478bd9Sstevel@tonic-gate *bp++ = '2'; 614*7c478bd9Sstevel@tonic-gate *bp++ = '0'; 615*7c478bd9Sstevel@tonic-gate linelen += 3; 616*7c478bd9Sstevel@tonic-gate } 617*7c478bd9Sstevel@tonic-gate else if (c2 == ' ' || c2 == '\t') 618*7c478bd9Sstevel@tonic-gate { 619*7c478bd9Sstevel@tonic-gate *bp++ = c2; 620*7c478bd9Sstevel@tonic-gate linelen++; 621*7c478bd9Sstevel@tonic-gate } 622*7c478bd9Sstevel@tonic-gate if (linelen > 72 && 623*7c478bd9Sstevel@tonic-gate (linelen > 75 || c1 != '.' || 624*7c478bd9Sstevel@tonic-gate (linelen > 73 && c2 == '.'))) 625*7c478bd9Sstevel@tonic-gate { 626*7c478bd9Sstevel@tonic-gate if (linelen > 73 && c2 == '.') 627*7c478bd9Sstevel@tonic-gate bp--; 628*7c478bd9Sstevel@tonic-gate else 629*7c478bd9Sstevel@tonic-gate c2 = '\n'; 630*7c478bd9Sstevel@tonic-gate *bp++ = '='; 631*7c478bd9Sstevel@tonic-gate *bp = '\0'; 632*7c478bd9Sstevel@tonic-gate putline(buf, mci); 633*7c478bd9Sstevel@tonic-gate linelen = fromstate = 0; 634*7c478bd9Sstevel@tonic-gate bp = buf; 635*7c478bd9Sstevel@tonic-gate if (c2 == '.') 636*7c478bd9Sstevel@tonic-gate { 637*7c478bd9Sstevel@tonic-gate *bp++ = '.'; 638*7c478bd9Sstevel@tonic-gate linelen++; 639*7c478bd9Sstevel@tonic-gate } 640*7c478bd9Sstevel@tonic-gate } 641*7c478bd9Sstevel@tonic-gate if (bitnset(bitidx(c1), badchars)) 642*7c478bd9Sstevel@tonic-gate { 643*7c478bd9Sstevel@tonic-gate *bp++ = '='; 644*7c478bd9Sstevel@tonic-gate *bp++ = Base16Code[(c1 >> 4) & 0x0f]; 645*7c478bd9Sstevel@tonic-gate *bp++ = Base16Code[c1 & 0x0f]; 646*7c478bd9Sstevel@tonic-gate linelen += 3; 647*7c478bd9Sstevel@tonic-gate } 648*7c478bd9Sstevel@tonic-gate else if (c1 != ' ' && c1 != '\t') 649*7c478bd9Sstevel@tonic-gate { 650*7c478bd9Sstevel@tonic-gate if (linelen < 4 && c1 == "From"[linelen]) 651*7c478bd9Sstevel@tonic-gate fromstate++; 652*7c478bd9Sstevel@tonic-gate *bp++ = c1; 653*7c478bd9Sstevel@tonic-gate linelen++; 654*7c478bd9Sstevel@tonic-gate } 655*7c478bd9Sstevel@tonic-gate c2 = c1; 656*7c478bd9Sstevel@tonic-gate } 657*7c478bd9Sstevel@tonic-gate 658*7c478bd9Sstevel@tonic-gate /* output any saved character */ 659*7c478bd9Sstevel@tonic-gate if (c2 == ' ' || c2 == '\t') 660*7c478bd9Sstevel@tonic-gate { 661*7c478bd9Sstevel@tonic-gate *bp++ = '='; 662*7c478bd9Sstevel@tonic-gate *bp++ = Base16Code[(c2 >> 4) & 0x0f]; 663*7c478bd9Sstevel@tonic-gate *bp++ = Base16Code[c2 & 0x0f]; 664*7c478bd9Sstevel@tonic-gate linelen += 3; 665*7c478bd9Sstevel@tonic-gate } 666*7c478bd9Sstevel@tonic-gate 667*7c478bd9Sstevel@tonic-gate if (linelen > 0 || boundaries[0] != NULL) 668*7c478bd9Sstevel@tonic-gate { 669*7c478bd9Sstevel@tonic-gate *bp = '\0'; 670*7c478bd9Sstevel@tonic-gate putline(buf, mci); 671*7c478bd9Sstevel@tonic-gate } 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate } 674*7c478bd9Sstevel@tonic-gate if (tTd(43, 3)) 675*7c478bd9Sstevel@tonic-gate sm_dprintf("\t\t\tmime8to7=>%s (basic)\n", MimeBoundaryNames[bt]); 676*7c478bd9Sstevel@tonic-gate return bt; 677*7c478bd9Sstevel@tonic-gate } 678*7c478bd9Sstevel@tonic-gate /* 679*7c478bd9Sstevel@tonic-gate ** MIME_GETCHAR -- get a character for MIME processing 680*7c478bd9Sstevel@tonic-gate ** 681*7c478bd9Sstevel@tonic-gate ** Treats boundaries as SM_IO_EOF. 682*7c478bd9Sstevel@tonic-gate ** 683*7c478bd9Sstevel@tonic-gate ** Parameters: 684*7c478bd9Sstevel@tonic-gate ** fp -- the input file. 685*7c478bd9Sstevel@tonic-gate ** boundaries -- the current MIME boundaries. 686*7c478bd9Sstevel@tonic-gate ** btp -- if the return value is SM_IO_EOF, *btp is set to 687*7c478bd9Sstevel@tonic-gate ** the type of the boundary. 688*7c478bd9Sstevel@tonic-gate ** 689*7c478bd9Sstevel@tonic-gate ** Returns: 690*7c478bd9Sstevel@tonic-gate ** The next character in the input stream. 691*7c478bd9Sstevel@tonic-gate */ 692*7c478bd9Sstevel@tonic-gate 693*7c478bd9Sstevel@tonic-gate static int 694*7c478bd9Sstevel@tonic-gate mime_getchar(fp, boundaries, btp) 695*7c478bd9Sstevel@tonic-gate register SM_FILE_T *fp; 696*7c478bd9Sstevel@tonic-gate char **boundaries; 697*7c478bd9Sstevel@tonic-gate int *btp; 698*7c478bd9Sstevel@tonic-gate { 699*7c478bd9Sstevel@tonic-gate int c; 700*7c478bd9Sstevel@tonic-gate static unsigned char *bp = NULL; 701*7c478bd9Sstevel@tonic-gate static int buflen = 0; 702*7c478bd9Sstevel@tonic-gate static bool atbol = true; /* at beginning of line */ 703*7c478bd9Sstevel@tonic-gate static int bt = MBT_SYNTAX; /* boundary type of next SM_IO_EOF */ 704*7c478bd9Sstevel@tonic-gate static unsigned char buf[128]; /* need not be a full line */ 705*7c478bd9Sstevel@tonic-gate int start = 0; /* indicates position of - in buffer */ 706*7c478bd9Sstevel@tonic-gate 707*7c478bd9Sstevel@tonic-gate if (buflen == 1 && *bp == '\n') 708*7c478bd9Sstevel@tonic-gate { 709*7c478bd9Sstevel@tonic-gate /* last \n in buffer may be part of next MIME boundary */ 710*7c478bd9Sstevel@tonic-gate c = *bp; 711*7c478bd9Sstevel@tonic-gate } 712*7c478bd9Sstevel@tonic-gate else if (buflen > 0) 713*7c478bd9Sstevel@tonic-gate { 714*7c478bd9Sstevel@tonic-gate buflen--; 715*7c478bd9Sstevel@tonic-gate return *bp++; 716*7c478bd9Sstevel@tonic-gate } 717*7c478bd9Sstevel@tonic-gate else 718*7c478bd9Sstevel@tonic-gate c = sm_io_getc(fp, SM_TIME_DEFAULT); 719*7c478bd9Sstevel@tonic-gate bp = buf; 720*7c478bd9Sstevel@tonic-gate buflen = 0; 721*7c478bd9Sstevel@tonic-gate if (c == '\n') 722*7c478bd9Sstevel@tonic-gate { 723*7c478bd9Sstevel@tonic-gate /* might be part of a MIME boundary */ 724*7c478bd9Sstevel@tonic-gate *bp++ = c; 725*7c478bd9Sstevel@tonic-gate atbol = true; 726*7c478bd9Sstevel@tonic-gate c = sm_io_getc(fp, SM_TIME_DEFAULT); 727*7c478bd9Sstevel@tonic-gate if (c == '\n') 728*7c478bd9Sstevel@tonic-gate { 729*7c478bd9Sstevel@tonic-gate (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c); 730*7c478bd9Sstevel@tonic-gate return c; 731*7c478bd9Sstevel@tonic-gate } 732*7c478bd9Sstevel@tonic-gate start = 1; 733*7c478bd9Sstevel@tonic-gate } 734*7c478bd9Sstevel@tonic-gate if (c != SM_IO_EOF) 735*7c478bd9Sstevel@tonic-gate *bp++ = c; 736*7c478bd9Sstevel@tonic-gate else 737*7c478bd9Sstevel@tonic-gate bt = MBT_FINAL; 738*7c478bd9Sstevel@tonic-gate if (atbol && c == '-') 739*7c478bd9Sstevel@tonic-gate { 740*7c478bd9Sstevel@tonic-gate /* check for a message boundary */ 741*7c478bd9Sstevel@tonic-gate c = sm_io_getc(fp, SM_TIME_DEFAULT); 742*7c478bd9Sstevel@tonic-gate if (c != '-') 743*7c478bd9Sstevel@tonic-gate { 744*7c478bd9Sstevel@tonic-gate if (c != SM_IO_EOF) 745*7c478bd9Sstevel@tonic-gate *bp++ = c; 746*7c478bd9Sstevel@tonic-gate else 747*7c478bd9Sstevel@tonic-gate bt = MBT_FINAL; 748*7c478bd9Sstevel@tonic-gate buflen = bp - buf - 1; 749*7c478bd9Sstevel@tonic-gate bp = buf; 750*7c478bd9Sstevel@tonic-gate return *bp++; 751*7c478bd9Sstevel@tonic-gate } 752*7c478bd9Sstevel@tonic-gate 753*7c478bd9Sstevel@tonic-gate /* got "--", now check for rest of separator */ 754*7c478bd9Sstevel@tonic-gate *bp++ = '-'; 755*7c478bd9Sstevel@tonic-gate while (bp < &buf[sizeof buf - 2] && 756*7c478bd9Sstevel@tonic-gate (c = sm_io_getc(fp, SM_TIME_DEFAULT)) != SM_IO_EOF && 757*7c478bd9Sstevel@tonic-gate c != '\n') 758*7c478bd9Sstevel@tonic-gate { 759*7c478bd9Sstevel@tonic-gate *bp++ = c; 760*7c478bd9Sstevel@tonic-gate } 761*7c478bd9Sstevel@tonic-gate *bp = '\0'; /* XXX simply cut off? */ 762*7c478bd9Sstevel@tonic-gate bt = mimeboundary((char *) &buf[start], boundaries); 763*7c478bd9Sstevel@tonic-gate switch (bt) 764*7c478bd9Sstevel@tonic-gate { 765*7c478bd9Sstevel@tonic-gate case MBT_FINAL: 766*7c478bd9Sstevel@tonic-gate case MBT_INTERMED: 767*7c478bd9Sstevel@tonic-gate /* we have a message boundary */ 768*7c478bd9Sstevel@tonic-gate buflen = 0; 769*7c478bd9Sstevel@tonic-gate *btp = bt; 770*7c478bd9Sstevel@tonic-gate return SM_IO_EOF; 771*7c478bd9Sstevel@tonic-gate } 772*7c478bd9Sstevel@tonic-gate 773*7c478bd9Sstevel@tonic-gate if (bp < &buf[sizeof buf - 2] && c != SM_IO_EOF) 774*7c478bd9Sstevel@tonic-gate *bp++ = c; 775*7c478bd9Sstevel@tonic-gate } 776*7c478bd9Sstevel@tonic-gate 777*7c478bd9Sstevel@tonic-gate atbol = c == '\n'; 778*7c478bd9Sstevel@tonic-gate buflen = bp - buf - 1; 779*7c478bd9Sstevel@tonic-gate if (buflen < 0) 780*7c478bd9Sstevel@tonic-gate { 781*7c478bd9Sstevel@tonic-gate *btp = bt; 782*7c478bd9Sstevel@tonic-gate return SM_IO_EOF; 783*7c478bd9Sstevel@tonic-gate } 784*7c478bd9Sstevel@tonic-gate bp = buf; 785*7c478bd9Sstevel@tonic-gate return *bp++; 786*7c478bd9Sstevel@tonic-gate } 787*7c478bd9Sstevel@tonic-gate /* 788*7c478bd9Sstevel@tonic-gate ** MIME_GETCHAR_CRLF -- do mime_getchar, but translate NL => CRLF 789*7c478bd9Sstevel@tonic-gate ** 790*7c478bd9Sstevel@tonic-gate ** Parameters: 791*7c478bd9Sstevel@tonic-gate ** fp -- the input file. 792*7c478bd9Sstevel@tonic-gate ** boundaries -- the current MIME boundaries. 793*7c478bd9Sstevel@tonic-gate ** btp -- if the return value is SM_IO_EOF, *btp is set to 794*7c478bd9Sstevel@tonic-gate ** the type of the boundary. 795*7c478bd9Sstevel@tonic-gate ** 796*7c478bd9Sstevel@tonic-gate ** Returns: 797*7c478bd9Sstevel@tonic-gate ** The next character in the input stream. 798*7c478bd9Sstevel@tonic-gate */ 799*7c478bd9Sstevel@tonic-gate 800*7c478bd9Sstevel@tonic-gate static int 801*7c478bd9Sstevel@tonic-gate mime_getchar_crlf(fp, boundaries, btp) 802*7c478bd9Sstevel@tonic-gate register SM_FILE_T *fp; 803*7c478bd9Sstevel@tonic-gate char **boundaries; 804*7c478bd9Sstevel@tonic-gate int *btp; 805*7c478bd9Sstevel@tonic-gate { 806*7c478bd9Sstevel@tonic-gate static bool sendlf = false; 807*7c478bd9Sstevel@tonic-gate int c; 808*7c478bd9Sstevel@tonic-gate 809*7c478bd9Sstevel@tonic-gate if (sendlf) 810*7c478bd9Sstevel@tonic-gate { 811*7c478bd9Sstevel@tonic-gate sendlf = false; 812*7c478bd9Sstevel@tonic-gate return '\n'; 813*7c478bd9Sstevel@tonic-gate } 814*7c478bd9Sstevel@tonic-gate c = mime_getchar(fp, boundaries, btp); 815*7c478bd9Sstevel@tonic-gate if (c == '\n' && MapNLtoCRLF) 816*7c478bd9Sstevel@tonic-gate { 817*7c478bd9Sstevel@tonic-gate sendlf = true; 818*7c478bd9Sstevel@tonic-gate return '\r'; 819*7c478bd9Sstevel@tonic-gate } 820*7c478bd9Sstevel@tonic-gate return c; 821*7c478bd9Sstevel@tonic-gate } 822*7c478bd9Sstevel@tonic-gate /* 823*7c478bd9Sstevel@tonic-gate ** MIMEBOUNDARY -- determine if this line is a MIME boundary & its type 824*7c478bd9Sstevel@tonic-gate ** 825*7c478bd9Sstevel@tonic-gate ** Parameters: 826*7c478bd9Sstevel@tonic-gate ** line -- the input line. 827*7c478bd9Sstevel@tonic-gate ** boundaries -- the set of currently pending boundaries. 828*7c478bd9Sstevel@tonic-gate ** 829*7c478bd9Sstevel@tonic-gate ** Returns: 830*7c478bd9Sstevel@tonic-gate ** MBT_NOTSEP -- if this is not a separator line 831*7c478bd9Sstevel@tonic-gate ** MBT_INTERMED -- if this is an intermediate separator 832*7c478bd9Sstevel@tonic-gate ** MBT_FINAL -- if this is a final boundary 833*7c478bd9Sstevel@tonic-gate ** MBT_SYNTAX -- if this is a boundary for the wrong 834*7c478bd9Sstevel@tonic-gate ** enclosure -- i.e., a syntax error. 835*7c478bd9Sstevel@tonic-gate */ 836*7c478bd9Sstevel@tonic-gate 837*7c478bd9Sstevel@tonic-gate static int 838*7c478bd9Sstevel@tonic-gate mimeboundary(line, boundaries) 839*7c478bd9Sstevel@tonic-gate register char *line; 840*7c478bd9Sstevel@tonic-gate char **boundaries; 841*7c478bd9Sstevel@tonic-gate { 842*7c478bd9Sstevel@tonic-gate int type = MBT_NOTSEP; 843*7c478bd9Sstevel@tonic-gate int i; 844*7c478bd9Sstevel@tonic-gate int savec; 845*7c478bd9Sstevel@tonic-gate 846*7c478bd9Sstevel@tonic-gate if (line[0] != '-' || line[1] != '-' || boundaries == NULL) 847*7c478bd9Sstevel@tonic-gate return MBT_NOTSEP; 848*7c478bd9Sstevel@tonic-gate i = strlen(line); 849*7c478bd9Sstevel@tonic-gate if (i > 0 && line[i - 1] == '\n') 850*7c478bd9Sstevel@tonic-gate i--; 851*7c478bd9Sstevel@tonic-gate 852*7c478bd9Sstevel@tonic-gate /* strip off trailing whitespace */ 853*7c478bd9Sstevel@tonic-gate while (i > 0 && (line[i - 1] == ' ' || line[i - 1] == '\t' 854*7c478bd9Sstevel@tonic-gate #if _FFR_MIME_CR_OK 855*7c478bd9Sstevel@tonic-gate || line[i - 1] == '\r' 856*7c478bd9Sstevel@tonic-gate #endif /* _FFR_MIME_CR_OK */ 857*7c478bd9Sstevel@tonic-gate )) 858*7c478bd9Sstevel@tonic-gate i--; 859*7c478bd9Sstevel@tonic-gate savec = line[i]; 860*7c478bd9Sstevel@tonic-gate line[i] = '\0'; 861*7c478bd9Sstevel@tonic-gate 862*7c478bd9Sstevel@tonic-gate if (tTd(43, 5)) 863*7c478bd9Sstevel@tonic-gate sm_dprintf("mimeboundary: line=\"%s\"... ", line); 864*7c478bd9Sstevel@tonic-gate 865*7c478bd9Sstevel@tonic-gate /* check for this as an intermediate boundary */ 866*7c478bd9Sstevel@tonic-gate if (isboundary(&line[2], boundaries) >= 0) 867*7c478bd9Sstevel@tonic-gate type = MBT_INTERMED; 868*7c478bd9Sstevel@tonic-gate else if (i > 2 && strncmp(&line[i - 2], "--", 2) == 0) 869*7c478bd9Sstevel@tonic-gate { 870*7c478bd9Sstevel@tonic-gate /* check for a final boundary */ 871*7c478bd9Sstevel@tonic-gate line[i - 2] = '\0'; 872*7c478bd9Sstevel@tonic-gate if (isboundary(&line[2], boundaries) >= 0) 873*7c478bd9Sstevel@tonic-gate type = MBT_FINAL; 874*7c478bd9Sstevel@tonic-gate line[i - 2] = '-'; 875*7c478bd9Sstevel@tonic-gate } 876*7c478bd9Sstevel@tonic-gate 877*7c478bd9Sstevel@tonic-gate line[i] = savec; 878*7c478bd9Sstevel@tonic-gate if (tTd(43, 5)) 879*7c478bd9Sstevel@tonic-gate sm_dprintf("%s\n", MimeBoundaryNames[type]); 880*7c478bd9Sstevel@tonic-gate return type; 881*7c478bd9Sstevel@tonic-gate } 882*7c478bd9Sstevel@tonic-gate /* 883*7c478bd9Sstevel@tonic-gate ** DEFCHARSET -- return default character set for message 884*7c478bd9Sstevel@tonic-gate ** 885*7c478bd9Sstevel@tonic-gate ** The first choice for character set is for the mailer 886*7c478bd9Sstevel@tonic-gate ** corresponding to the envelope sender. If neither that 887*7c478bd9Sstevel@tonic-gate ** nor the global configuration file has a default character 888*7c478bd9Sstevel@tonic-gate ** set defined, return "unknown-8bit" as recommended by 889*7c478bd9Sstevel@tonic-gate ** RFC 1428 section 3. 890*7c478bd9Sstevel@tonic-gate ** 891*7c478bd9Sstevel@tonic-gate ** Parameters: 892*7c478bd9Sstevel@tonic-gate ** e -- the envelope for this message. 893*7c478bd9Sstevel@tonic-gate ** 894*7c478bd9Sstevel@tonic-gate ** Returns: 895*7c478bd9Sstevel@tonic-gate ** The default character set for that mailer. 896*7c478bd9Sstevel@tonic-gate */ 897*7c478bd9Sstevel@tonic-gate 898*7c478bd9Sstevel@tonic-gate char * 899*7c478bd9Sstevel@tonic-gate defcharset(e) 900*7c478bd9Sstevel@tonic-gate register ENVELOPE *e; 901*7c478bd9Sstevel@tonic-gate { 902*7c478bd9Sstevel@tonic-gate if (e != NULL && e->e_from.q_mailer != NULL && 903*7c478bd9Sstevel@tonic-gate e->e_from.q_mailer->m_defcharset != NULL) 904*7c478bd9Sstevel@tonic-gate return e->e_from.q_mailer->m_defcharset; 905*7c478bd9Sstevel@tonic-gate if (DefaultCharSet != NULL) 906*7c478bd9Sstevel@tonic-gate return DefaultCharSet; 907*7c478bd9Sstevel@tonic-gate return "unknown-8bit"; 908*7c478bd9Sstevel@tonic-gate } 909*7c478bd9Sstevel@tonic-gate /* 910*7c478bd9Sstevel@tonic-gate ** ISBOUNDARY -- is a given string a currently valid boundary? 911*7c478bd9Sstevel@tonic-gate ** 912*7c478bd9Sstevel@tonic-gate ** Parameters: 913*7c478bd9Sstevel@tonic-gate ** line -- the current input line. 914*7c478bd9Sstevel@tonic-gate ** boundaries -- the list of valid boundaries. 915*7c478bd9Sstevel@tonic-gate ** 916*7c478bd9Sstevel@tonic-gate ** Returns: 917*7c478bd9Sstevel@tonic-gate ** The index number in boundaries if the line is found. 918*7c478bd9Sstevel@tonic-gate ** -1 -- otherwise. 919*7c478bd9Sstevel@tonic-gate ** 920*7c478bd9Sstevel@tonic-gate */ 921*7c478bd9Sstevel@tonic-gate 922*7c478bd9Sstevel@tonic-gate static int 923*7c478bd9Sstevel@tonic-gate isboundary(line, boundaries) 924*7c478bd9Sstevel@tonic-gate char *line; 925*7c478bd9Sstevel@tonic-gate char **boundaries; 926*7c478bd9Sstevel@tonic-gate { 927*7c478bd9Sstevel@tonic-gate register int i; 928*7c478bd9Sstevel@tonic-gate 929*7c478bd9Sstevel@tonic-gate for (i = 0; i <= MAXMIMENESTING && boundaries[i] != NULL; i++) 930*7c478bd9Sstevel@tonic-gate { 931*7c478bd9Sstevel@tonic-gate if (strcmp(line, boundaries[i]) == 0) 932*7c478bd9Sstevel@tonic-gate return i; 933*7c478bd9Sstevel@tonic-gate } 934*7c478bd9Sstevel@tonic-gate return -1; 935*7c478bd9Sstevel@tonic-gate } 936*7c478bd9Sstevel@tonic-gate #endif /* MIME8TO7 */ 937*7c478bd9Sstevel@tonic-gate 938*7c478bd9Sstevel@tonic-gate #if MIME7TO8 939*7c478bd9Sstevel@tonic-gate static int mime_fromqp __P((unsigned char *, unsigned char **, int)); 940*7c478bd9Sstevel@tonic-gate 941*7c478bd9Sstevel@tonic-gate /* 942*7c478bd9Sstevel@tonic-gate ** MIME7TO8 -- output 7 bit encoded MIME body in 8 bit format 943*7c478bd9Sstevel@tonic-gate ** 944*7c478bd9Sstevel@tonic-gate ** This is a hack. Supports translating the two 7-bit body-encodings 945*7c478bd9Sstevel@tonic-gate ** (quoted-printable and base64) to 8-bit coded bodies. 946*7c478bd9Sstevel@tonic-gate ** 947*7c478bd9Sstevel@tonic-gate ** There is not much point in supporting multipart here, as the UA 948*7c478bd9Sstevel@tonic-gate ** will be able to deal with encoded MIME bodies if it can parse MIME 949*7c478bd9Sstevel@tonic-gate ** multipart messages. 950*7c478bd9Sstevel@tonic-gate ** 951*7c478bd9Sstevel@tonic-gate ** Note also that we won't be called unless it is a text/plain MIME 952*7c478bd9Sstevel@tonic-gate ** message, encoded base64 or QP and mailer flag '9' has been defined 953*7c478bd9Sstevel@tonic-gate ** on mailer. 954*7c478bd9Sstevel@tonic-gate ** 955*7c478bd9Sstevel@tonic-gate ** Contributed by Marius Olaffson <marius@rhi.hi.is>. 956*7c478bd9Sstevel@tonic-gate ** 957*7c478bd9Sstevel@tonic-gate ** Parameters: 958*7c478bd9Sstevel@tonic-gate ** mci -- mailer connection information. 959*7c478bd9Sstevel@tonic-gate ** header -- the header for this body part. 960*7c478bd9Sstevel@tonic-gate ** e -- envelope. 961*7c478bd9Sstevel@tonic-gate ** 962*7c478bd9Sstevel@tonic-gate ** Returns: 963*7c478bd9Sstevel@tonic-gate ** none. 964*7c478bd9Sstevel@tonic-gate */ 965*7c478bd9Sstevel@tonic-gate 966*7c478bd9Sstevel@tonic-gate static char index_64[128] = 967*7c478bd9Sstevel@tonic-gate { 968*7c478bd9Sstevel@tonic-gate -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, 969*7c478bd9Sstevel@tonic-gate -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, 970*7c478bd9Sstevel@tonic-gate -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, 971*7c478bd9Sstevel@tonic-gate 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, 972*7c478bd9Sstevel@tonic-gate -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, 973*7c478bd9Sstevel@tonic-gate 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, 974*7c478bd9Sstevel@tonic-gate -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, 975*7c478bd9Sstevel@tonic-gate 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 976*7c478bd9Sstevel@tonic-gate }; 977*7c478bd9Sstevel@tonic-gate 978*7c478bd9Sstevel@tonic-gate # define CHAR64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)]) 979*7c478bd9Sstevel@tonic-gate 980*7c478bd9Sstevel@tonic-gate void 981*7c478bd9Sstevel@tonic-gate mime7to8(mci, header, e) 982*7c478bd9Sstevel@tonic-gate register MCI *mci; 983*7c478bd9Sstevel@tonic-gate HDR *header; 984*7c478bd9Sstevel@tonic-gate register ENVELOPE *e; 985*7c478bd9Sstevel@tonic-gate { 986*7c478bd9Sstevel@tonic-gate int pxflags; 987*7c478bd9Sstevel@tonic-gate register char *p; 988*7c478bd9Sstevel@tonic-gate char *cte; 989*7c478bd9Sstevel@tonic-gate char **pvp; 990*7c478bd9Sstevel@tonic-gate unsigned char *fbufp; 991*7c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 992*7c478bd9Sstevel@tonic-gate unsigned char fbuf[MAXLINE + 1]; 993*7c478bd9Sstevel@tonic-gate char pvpbuf[MAXLINE]; 994*7c478bd9Sstevel@tonic-gate extern unsigned char MimeTokenTab[256]; 995*7c478bd9Sstevel@tonic-gate 996*7c478bd9Sstevel@tonic-gate p = hvalue("Content-Transfer-Encoding", header); 997*7c478bd9Sstevel@tonic-gate if (p == NULL || 998*7c478bd9Sstevel@tonic-gate (pvp = prescan(p, '\0', pvpbuf, sizeof pvpbuf, NULL, 999*7c478bd9Sstevel@tonic-gate MimeTokenTab, false)) == NULL || 1000*7c478bd9Sstevel@tonic-gate pvp[0] == NULL) 1001*7c478bd9Sstevel@tonic-gate { 1002*7c478bd9Sstevel@tonic-gate /* "can't happen" -- upper level should have caught this */ 1003*7c478bd9Sstevel@tonic-gate syserr("mime7to8: unparsable CTE %s", p == NULL ? "<NULL>" : p); 1004*7c478bd9Sstevel@tonic-gate 1005*7c478bd9Sstevel@tonic-gate /* avoid bounce loops */ 1006*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_DONT_MIME; 1007*7c478bd9Sstevel@tonic-gate 1008*7c478bd9Sstevel@tonic-gate /* cheap failsafe algorithm -- should work on text/plain */ 1009*7c478bd9Sstevel@tonic-gate if (p != NULL) 1010*7c478bd9Sstevel@tonic-gate { 1011*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, 1012*7c478bd9Sstevel@tonic-gate "Content-Transfer-Encoding: %s", p); 1013*7c478bd9Sstevel@tonic-gate putline(buf, mci); 1014*7c478bd9Sstevel@tonic-gate } 1015*7c478bd9Sstevel@tonic-gate putline("", mci); 1016*7c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_INHEADER; 1017*7c478bd9Sstevel@tonic-gate while (sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, sizeof buf) 1018*7c478bd9Sstevel@tonic-gate != NULL) 1019*7c478bd9Sstevel@tonic-gate putline(buf, mci); 1020*7c478bd9Sstevel@tonic-gate return; 1021*7c478bd9Sstevel@tonic-gate } 1022*7c478bd9Sstevel@tonic-gate cataddr(pvp, NULL, buf, sizeof buf, '\0'); 1023*7c478bd9Sstevel@tonic-gate cte = sm_rpool_strdup_x(e->e_rpool, buf); 1024*7c478bd9Sstevel@tonic-gate 1025*7c478bd9Sstevel@tonic-gate mci->mci_flags |= MCIF_INHEADER; 1026*7c478bd9Sstevel@tonic-gate putline("Content-Transfer-Encoding: 8bit", mci); 1027*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, 1028*7c478bd9Sstevel@tonic-gate "X-MIME-Autoconverted: from %.200s to 8bit by %s id %s", 1029*7c478bd9Sstevel@tonic-gate cte, MyHostName, e->e_id); 1030*7c478bd9Sstevel@tonic-gate putline(buf, mci); 1031*7c478bd9Sstevel@tonic-gate putline("", mci); 1032*7c478bd9Sstevel@tonic-gate mci->mci_flags &= ~MCIF_INHEADER; 1033*7c478bd9Sstevel@tonic-gate 1034*7c478bd9Sstevel@tonic-gate /* 1035*7c478bd9Sstevel@tonic-gate ** Translate body encoding to 8-bit. Supports two types of 1036*7c478bd9Sstevel@tonic-gate ** encodings; "base64" and "quoted-printable". Assume qp if 1037*7c478bd9Sstevel@tonic-gate ** it is not base64. 1038*7c478bd9Sstevel@tonic-gate */ 1039*7c478bd9Sstevel@tonic-gate 1040*7c478bd9Sstevel@tonic-gate pxflags = PXLF_MAPFROM; 1041*7c478bd9Sstevel@tonic-gate if (sm_strcasecmp(cte, "base64") == 0) 1042*7c478bd9Sstevel@tonic-gate { 1043*7c478bd9Sstevel@tonic-gate int c1, c2, c3, c4; 1044*7c478bd9Sstevel@tonic-gate 1045*7c478bd9Sstevel@tonic-gate fbufp = fbuf; 1046*7c478bd9Sstevel@tonic-gate while ((c1 = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT)) != 1047*7c478bd9Sstevel@tonic-gate SM_IO_EOF) 1048*7c478bd9Sstevel@tonic-gate { 1049*7c478bd9Sstevel@tonic-gate if (isascii(c1) && isspace(c1)) 1050*7c478bd9Sstevel@tonic-gate continue; 1051*7c478bd9Sstevel@tonic-gate 1052*7c478bd9Sstevel@tonic-gate do 1053*7c478bd9Sstevel@tonic-gate { 1054*7c478bd9Sstevel@tonic-gate c2 = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT); 1055*7c478bd9Sstevel@tonic-gate } while (isascii(c2) && isspace(c2)); 1056*7c478bd9Sstevel@tonic-gate if (c2 == SM_IO_EOF) 1057*7c478bd9Sstevel@tonic-gate break; 1058*7c478bd9Sstevel@tonic-gate 1059*7c478bd9Sstevel@tonic-gate do 1060*7c478bd9Sstevel@tonic-gate { 1061*7c478bd9Sstevel@tonic-gate c3 = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT); 1062*7c478bd9Sstevel@tonic-gate } while (isascii(c3) && isspace(c3)); 1063*7c478bd9Sstevel@tonic-gate if (c3 == SM_IO_EOF) 1064*7c478bd9Sstevel@tonic-gate break; 1065*7c478bd9Sstevel@tonic-gate 1066*7c478bd9Sstevel@tonic-gate do 1067*7c478bd9Sstevel@tonic-gate { 1068*7c478bd9Sstevel@tonic-gate c4 = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT); 1069*7c478bd9Sstevel@tonic-gate } while (isascii(c4) && isspace(c4)); 1070*7c478bd9Sstevel@tonic-gate if (c4 == SM_IO_EOF) 1071*7c478bd9Sstevel@tonic-gate break; 1072*7c478bd9Sstevel@tonic-gate 1073*7c478bd9Sstevel@tonic-gate if (c1 == '=' || c2 == '=') 1074*7c478bd9Sstevel@tonic-gate continue; 1075*7c478bd9Sstevel@tonic-gate c1 = CHAR64(c1); 1076*7c478bd9Sstevel@tonic-gate c2 = CHAR64(c2); 1077*7c478bd9Sstevel@tonic-gate 1078*7c478bd9Sstevel@tonic-gate #if MIME7TO8_OLD 1079*7c478bd9Sstevel@tonic-gate #define CHK_EOL if (*--fbufp != '\n' || (fbufp > fbuf && *--fbufp != '\r')) \ 1080*7c478bd9Sstevel@tonic-gate ++fbufp; 1081*7c478bd9Sstevel@tonic-gate #else /* MIME7TO8_OLD */ 1082*7c478bd9Sstevel@tonic-gate #define CHK_EOL if (*--fbufp != '\n' || (fbufp > fbuf && *--fbufp != '\r')) \ 1083*7c478bd9Sstevel@tonic-gate { \ 1084*7c478bd9Sstevel@tonic-gate ++fbufp; \ 1085*7c478bd9Sstevel@tonic-gate pxflags |= PXLF_NOADDEOL; \ 1086*7c478bd9Sstevel@tonic-gate } 1087*7c478bd9Sstevel@tonic-gate #endif /* MIME7TO8_OLD */ 1088*7c478bd9Sstevel@tonic-gate 1089*7c478bd9Sstevel@tonic-gate #define PUTLINE64 \ 1090*7c478bd9Sstevel@tonic-gate do \ 1091*7c478bd9Sstevel@tonic-gate { \ 1092*7c478bd9Sstevel@tonic-gate if (*fbufp++ == '\n' || fbufp >= &fbuf[MAXLINE]) \ 1093*7c478bd9Sstevel@tonic-gate { \ 1094*7c478bd9Sstevel@tonic-gate CHK_EOL; \ 1095*7c478bd9Sstevel@tonic-gate putxline((char *) fbuf, fbufp - fbuf, mci, pxflags); \ 1096*7c478bd9Sstevel@tonic-gate pxflags &= ~PXLF_NOADDEOL; \ 1097*7c478bd9Sstevel@tonic-gate fbufp = fbuf; \ 1098*7c478bd9Sstevel@tonic-gate } \ 1099*7c478bd9Sstevel@tonic-gate } while (0) 1100*7c478bd9Sstevel@tonic-gate 1101*7c478bd9Sstevel@tonic-gate *fbufp = (c1 << 2) | ((c2 & 0x30) >> 4); 1102*7c478bd9Sstevel@tonic-gate PUTLINE64; 1103*7c478bd9Sstevel@tonic-gate if (c3 == '=') 1104*7c478bd9Sstevel@tonic-gate continue; 1105*7c478bd9Sstevel@tonic-gate c3 = CHAR64(c3); 1106*7c478bd9Sstevel@tonic-gate *fbufp = ((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2); 1107*7c478bd9Sstevel@tonic-gate PUTLINE64; 1108*7c478bd9Sstevel@tonic-gate if (c4 == '=') 1109*7c478bd9Sstevel@tonic-gate continue; 1110*7c478bd9Sstevel@tonic-gate c4 = CHAR64(c4); 1111*7c478bd9Sstevel@tonic-gate *fbufp = ((c3 & 0x03) << 6) | c4; 1112*7c478bd9Sstevel@tonic-gate PUTLINE64; 1113*7c478bd9Sstevel@tonic-gate } 1114*7c478bd9Sstevel@tonic-gate } 1115*7c478bd9Sstevel@tonic-gate else 1116*7c478bd9Sstevel@tonic-gate { 1117*7c478bd9Sstevel@tonic-gate int off; 1118*7c478bd9Sstevel@tonic-gate 1119*7c478bd9Sstevel@tonic-gate /* quoted-printable */ 1120*7c478bd9Sstevel@tonic-gate pxflags |= PXLF_NOADDEOL; 1121*7c478bd9Sstevel@tonic-gate fbufp = fbuf; 1122*7c478bd9Sstevel@tonic-gate while (sm_io_fgets(e->e_dfp, SM_TIME_DEFAULT, buf, 1123*7c478bd9Sstevel@tonic-gate sizeof buf) != NULL) 1124*7c478bd9Sstevel@tonic-gate { 1125*7c478bd9Sstevel@tonic-gate off = mime_fromqp((unsigned char *) buf, &fbufp, 1126*7c478bd9Sstevel@tonic-gate &fbuf[MAXLINE] - fbufp); 1127*7c478bd9Sstevel@tonic-gate again: 1128*7c478bd9Sstevel@tonic-gate if (off < -1) 1129*7c478bd9Sstevel@tonic-gate continue; 1130*7c478bd9Sstevel@tonic-gate 1131*7c478bd9Sstevel@tonic-gate if (fbufp - fbuf > 0) 1132*7c478bd9Sstevel@tonic-gate putxline((char *) fbuf, fbufp - fbuf - 1, mci, 1133*7c478bd9Sstevel@tonic-gate pxflags); 1134*7c478bd9Sstevel@tonic-gate fbufp = fbuf; 1135*7c478bd9Sstevel@tonic-gate if (off >= 0 && buf[off] != '\0') 1136*7c478bd9Sstevel@tonic-gate { 1137*7c478bd9Sstevel@tonic-gate off = mime_fromqp((unsigned char *) (buf + off), 1138*7c478bd9Sstevel@tonic-gate &fbufp, 1139*7c478bd9Sstevel@tonic-gate &fbuf[MAXLINE] - fbufp); 1140*7c478bd9Sstevel@tonic-gate goto again; 1141*7c478bd9Sstevel@tonic-gate } 1142*7c478bd9Sstevel@tonic-gate } 1143*7c478bd9Sstevel@tonic-gate } 1144*7c478bd9Sstevel@tonic-gate 1145*7c478bd9Sstevel@tonic-gate /* force out partial last line */ 1146*7c478bd9Sstevel@tonic-gate if (fbufp > fbuf) 1147*7c478bd9Sstevel@tonic-gate { 1148*7c478bd9Sstevel@tonic-gate *fbufp = '\0'; 1149*7c478bd9Sstevel@tonic-gate putxline((char *) fbuf, fbufp - fbuf, mci, pxflags); 1150*7c478bd9Sstevel@tonic-gate } 1151*7c478bd9Sstevel@tonic-gate 1152*7c478bd9Sstevel@tonic-gate /* 1153*7c478bd9Sstevel@tonic-gate ** The decoded text may end without an EOL. Since this function 1154*7c478bd9Sstevel@tonic-gate ** is only called for text/plain MIME messages, it is safe to 1155*7c478bd9Sstevel@tonic-gate ** add an extra one at the end just in case. This is a hack, 1156*7c478bd9Sstevel@tonic-gate ** but so is auto-converting MIME in the first place. 1157*7c478bd9Sstevel@tonic-gate */ 1158*7c478bd9Sstevel@tonic-gate 1159*7c478bd9Sstevel@tonic-gate putline("", mci); 1160*7c478bd9Sstevel@tonic-gate 1161*7c478bd9Sstevel@tonic-gate if (tTd(43, 3)) 1162*7c478bd9Sstevel@tonic-gate sm_dprintf("\t\t\tmime7to8 => %s to 8bit done\n", cte); 1163*7c478bd9Sstevel@tonic-gate } 1164*7c478bd9Sstevel@tonic-gate /* 1165*7c478bd9Sstevel@tonic-gate ** The following is based on Borenstein's "codes.c" module, with simplifying 1166*7c478bd9Sstevel@tonic-gate ** changes as we do not deal with multipart, and to do the translation in-core, 1167*7c478bd9Sstevel@tonic-gate ** with an attempt to prevent overrun of output buffers. 1168*7c478bd9Sstevel@tonic-gate ** 1169*7c478bd9Sstevel@tonic-gate ** What is needed here are changes to defend this code better against 1170*7c478bd9Sstevel@tonic-gate ** bad encodings. Questionable to always return 0xFF for bad mappings. 1171*7c478bd9Sstevel@tonic-gate */ 1172*7c478bd9Sstevel@tonic-gate 1173*7c478bd9Sstevel@tonic-gate static char index_hex[128] = 1174*7c478bd9Sstevel@tonic-gate { 1175*7c478bd9Sstevel@tonic-gate -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, 1176*7c478bd9Sstevel@tonic-gate -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, 1177*7c478bd9Sstevel@tonic-gate -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, 1178*7c478bd9Sstevel@tonic-gate 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1, 1179*7c478bd9Sstevel@tonic-gate -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, 1180*7c478bd9Sstevel@tonic-gate -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, 1181*7c478bd9Sstevel@tonic-gate -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, 1182*7c478bd9Sstevel@tonic-gate -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1 1183*7c478bd9Sstevel@tonic-gate }; 1184*7c478bd9Sstevel@tonic-gate 1185*7c478bd9Sstevel@tonic-gate # define HEXCHAR(c) (((c) < 0 || (c) > 127) ? -1 : index_hex[(c)]) 1186*7c478bd9Sstevel@tonic-gate 1187*7c478bd9Sstevel@tonic-gate /* 1188*7c478bd9Sstevel@tonic-gate ** MIME_FROMQP -- decode quoted printable string 1189*7c478bd9Sstevel@tonic-gate ** 1190*7c478bd9Sstevel@tonic-gate ** Parameters: 1191*7c478bd9Sstevel@tonic-gate ** infile -- input (encoded) string 1192*7c478bd9Sstevel@tonic-gate ** outfile -- output string 1193*7c478bd9Sstevel@tonic-gate ** maxlen -- size of output buffer 1194*7c478bd9Sstevel@tonic-gate ** 1195*7c478bd9Sstevel@tonic-gate ** Returns: 1196*7c478bd9Sstevel@tonic-gate ** -2 if decoding failure 1197*7c478bd9Sstevel@tonic-gate ** -1 if infile completely decoded into outfile 1198*7c478bd9Sstevel@tonic-gate ** >= 0 is the position in infile decoding 1199*7c478bd9Sstevel@tonic-gate ** reached before maxlen was reached 1200*7c478bd9Sstevel@tonic-gate */ 1201*7c478bd9Sstevel@tonic-gate 1202*7c478bd9Sstevel@tonic-gate static int 1203*7c478bd9Sstevel@tonic-gate mime_fromqp(infile, outfile, maxlen) 1204*7c478bd9Sstevel@tonic-gate unsigned char *infile; 1205*7c478bd9Sstevel@tonic-gate unsigned char **outfile; 1206*7c478bd9Sstevel@tonic-gate int maxlen; /* Max # of chars allowed in outfile */ 1207*7c478bd9Sstevel@tonic-gate { 1208*7c478bd9Sstevel@tonic-gate int c1, c2; 1209*7c478bd9Sstevel@tonic-gate int nchar = 0; 1210*7c478bd9Sstevel@tonic-gate unsigned char *b; 1211*7c478bd9Sstevel@tonic-gate 1212*7c478bd9Sstevel@tonic-gate /* decrement by one for trailing '\0', at least one other char */ 1213*7c478bd9Sstevel@tonic-gate if (--maxlen < 1) 1214*7c478bd9Sstevel@tonic-gate return 0; 1215*7c478bd9Sstevel@tonic-gate 1216*7c478bd9Sstevel@tonic-gate b = infile; 1217*7c478bd9Sstevel@tonic-gate while ((c1 = *infile++) != '\0' && nchar < maxlen) 1218*7c478bd9Sstevel@tonic-gate { 1219*7c478bd9Sstevel@tonic-gate if (c1 == '=') 1220*7c478bd9Sstevel@tonic-gate { 1221*7c478bd9Sstevel@tonic-gate if ((c1 = *infile++) == '\0') 1222*7c478bd9Sstevel@tonic-gate break; 1223*7c478bd9Sstevel@tonic-gate 1224*7c478bd9Sstevel@tonic-gate if (c1 == '\n' || (c1 = HEXCHAR(c1)) == -1) 1225*7c478bd9Sstevel@tonic-gate { 1226*7c478bd9Sstevel@tonic-gate /* ignore it and the rest of the buffer */ 1227*7c478bd9Sstevel@tonic-gate return -2; 1228*7c478bd9Sstevel@tonic-gate } 1229*7c478bd9Sstevel@tonic-gate else 1230*7c478bd9Sstevel@tonic-gate { 1231*7c478bd9Sstevel@tonic-gate do 1232*7c478bd9Sstevel@tonic-gate { 1233*7c478bd9Sstevel@tonic-gate if ((c2 = *infile++) == '\0') 1234*7c478bd9Sstevel@tonic-gate { 1235*7c478bd9Sstevel@tonic-gate c2 = -1; 1236*7c478bd9Sstevel@tonic-gate break; 1237*7c478bd9Sstevel@tonic-gate } 1238*7c478bd9Sstevel@tonic-gate } while ((c2 = HEXCHAR(c2)) == -1); 1239*7c478bd9Sstevel@tonic-gate 1240*7c478bd9Sstevel@tonic-gate if (c2 == -1) 1241*7c478bd9Sstevel@tonic-gate break; 1242*7c478bd9Sstevel@tonic-gate nchar++; 1243*7c478bd9Sstevel@tonic-gate *(*outfile)++ = c1 << 4 | c2; 1244*7c478bd9Sstevel@tonic-gate } 1245*7c478bd9Sstevel@tonic-gate } 1246*7c478bd9Sstevel@tonic-gate else 1247*7c478bd9Sstevel@tonic-gate { 1248*7c478bd9Sstevel@tonic-gate nchar++; 1249*7c478bd9Sstevel@tonic-gate *(*outfile)++ = c1; 1250*7c478bd9Sstevel@tonic-gate if (c1 == '\n') 1251*7c478bd9Sstevel@tonic-gate break; 1252*7c478bd9Sstevel@tonic-gate } 1253*7c478bd9Sstevel@tonic-gate } 1254*7c478bd9Sstevel@tonic-gate *(*outfile)++ = '\0'; 1255*7c478bd9Sstevel@tonic-gate if (nchar >= maxlen) 1256*7c478bd9Sstevel@tonic-gate return (infile - b - 1); 1257*7c478bd9Sstevel@tonic-gate return -1; 1258*7c478bd9Sstevel@tonic-gate } 1259*7c478bd9Sstevel@tonic-gate #endif /* MIME7TO8 */ 1260