1c2aa98e2SPeter Wemm /* 23299c2f1SGregory Neil Shapiro * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. 33299c2f1SGregory Neil Shapiro * All rights reserved. 4c2aa98e2SPeter Wemm * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5c2aa98e2SPeter Wemm * Copyright (c) 1988, 1993 6c2aa98e2SPeter Wemm * The Regents of the University of California. All rights reserved. 7c2aa98e2SPeter Wemm * 8c2aa98e2SPeter Wemm * By using this file, you agree to the terms and conditions set 9c2aa98e2SPeter Wemm * forth in the LICENSE file which can be found at the top level of 10c2aa98e2SPeter Wemm * the sendmail distribution. 11c2aa98e2SPeter Wemm * 12c2aa98e2SPeter Wemm */ 13c2aa98e2SPeter Wemm 14c2aa98e2SPeter Wemm #ifndef lint 15c46d91b7SGregory Neil Shapiro static char id[] = "@(#)$Id: headers.c,v 8.203.4.10 2000/10/13 17:54:30 gshapiro Exp $"; 163299c2f1SGregory Neil Shapiro #endif /* ! lint */ 17c2aa98e2SPeter Wemm 183299c2f1SGregory Neil Shapiro /* $FreeBSD$ */ 193299c2f1SGregory Neil Shapiro 203299c2f1SGregory Neil Shapiro #include <sendmail.h> 213299c2f1SGregory Neil Shapiro 22c46d91b7SGregory Neil Shapiro static size_t fix_mime_header __P((char *)); 233299c2f1SGregory Neil Shapiro static int priencode __P((char *)); 243299c2f1SGregory Neil Shapiro static void put_vanilla_header __P((HDR *, char *, MCI *)); 25c2aa98e2SPeter Wemm 26c2aa98e2SPeter Wemm /* 27c2aa98e2SPeter Wemm ** SETUPHEADERS -- initialize headers in symbol table 28c2aa98e2SPeter Wemm ** 29c2aa98e2SPeter Wemm ** Parameters: 30c2aa98e2SPeter Wemm ** none 31c2aa98e2SPeter Wemm ** 32c2aa98e2SPeter Wemm ** Returns: 33c2aa98e2SPeter Wemm ** none 34c2aa98e2SPeter Wemm */ 35c2aa98e2SPeter Wemm 36c2aa98e2SPeter Wemm void 37c2aa98e2SPeter Wemm setupheaders() 38c2aa98e2SPeter Wemm { 39c2aa98e2SPeter Wemm struct hdrinfo *hi; 40c2aa98e2SPeter Wemm STAB *s; 41c2aa98e2SPeter Wemm 42c2aa98e2SPeter Wemm for (hi = HdrInfo; hi->hi_field != NULL; hi++) 43c2aa98e2SPeter Wemm { 44c2aa98e2SPeter Wemm s = stab(hi->hi_field, ST_HEADER, ST_ENTER); 45c2aa98e2SPeter Wemm s->s_header.hi_flags = hi->hi_flags; 46c2aa98e2SPeter Wemm s->s_header.hi_ruleset = NULL; 47c2aa98e2SPeter Wemm } 48c2aa98e2SPeter Wemm } 49c2aa98e2SPeter Wemm /* 50c2aa98e2SPeter Wemm ** CHOMPHEADER -- process and save a header line. 51c2aa98e2SPeter Wemm ** 523299c2f1SGregory Neil Shapiro ** Called by collect, readcf, and readqf to deal with header lines. 53c2aa98e2SPeter Wemm ** 54c2aa98e2SPeter Wemm ** Parameters: 55c2aa98e2SPeter Wemm ** line -- header as a text line. 56d995d2baSGregory Neil Shapiro ** pflag -- flags for chompheader() (from sendmail.h) 57c2aa98e2SPeter Wemm ** hdrp -- a pointer to the place to save the header. 58c2aa98e2SPeter Wemm ** e -- the envelope including this header. 59c2aa98e2SPeter Wemm ** 60c2aa98e2SPeter Wemm ** Returns: 61c2aa98e2SPeter Wemm ** flags for this header. 62c2aa98e2SPeter Wemm ** 63c2aa98e2SPeter Wemm ** Side Effects: 64c2aa98e2SPeter Wemm ** The header is saved on the header list. 65c2aa98e2SPeter Wemm ** Contents of 'line' are destroyed. 66c2aa98e2SPeter Wemm */ 67c2aa98e2SPeter Wemm 683299c2f1SGregory Neil Shapiro static struct hdrinfo NormalHeader = { NULL, 0, NULL }; 69c2aa98e2SPeter Wemm 703299c2f1SGregory Neil Shapiro u_long 713299c2f1SGregory Neil Shapiro chompheader(line, pflag, hdrp, e) 72c2aa98e2SPeter Wemm char *line; 733299c2f1SGregory Neil Shapiro int pflag; 74c2aa98e2SPeter Wemm HDR **hdrp; 75c2aa98e2SPeter Wemm register ENVELOPE *e; 76c2aa98e2SPeter Wemm { 773299c2f1SGregory Neil Shapiro u_char mid = '\0'; 78c2aa98e2SPeter Wemm register char *p; 79c2aa98e2SPeter Wemm register HDR *h; 80c2aa98e2SPeter Wemm HDR **hp; 81c2aa98e2SPeter Wemm char *fname; 82c2aa98e2SPeter Wemm char *fvalue; 83c2aa98e2SPeter Wemm bool cond = FALSE; 843299c2f1SGregory Neil Shapiro bool dropfrom; 85c2aa98e2SPeter Wemm bool headeronly; 86c2aa98e2SPeter Wemm STAB *s; 87c2aa98e2SPeter Wemm struct hdrinfo *hi; 88e01d6f61SPeter Wemm bool nullheader = FALSE; 893299c2f1SGregory Neil Shapiro BITMAP256 mopts; 90c2aa98e2SPeter Wemm 91c2aa98e2SPeter Wemm if (tTd(31, 6)) 92c2aa98e2SPeter Wemm { 933299c2f1SGregory Neil Shapiro dprintf("chompheader: "); 94c2aa98e2SPeter Wemm xputs(line); 953299c2f1SGregory Neil Shapiro dprintf("\n"); 96c2aa98e2SPeter Wemm } 97c2aa98e2SPeter Wemm 98c2aa98e2SPeter Wemm headeronly = hdrp != NULL; 99c2aa98e2SPeter Wemm if (!headeronly) 100c2aa98e2SPeter Wemm hdrp = &e->e_header; 101c2aa98e2SPeter Wemm 102c2aa98e2SPeter Wemm /* strip off options */ 103c2aa98e2SPeter Wemm clrbitmap(mopts); 104c2aa98e2SPeter Wemm p = line; 1053299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_USER) && *p == '?') 106c2aa98e2SPeter Wemm { 1073299c2f1SGregory Neil Shapiro int c; 1083299c2f1SGregory Neil Shapiro register char *q; 109c2aa98e2SPeter Wemm 1103299c2f1SGregory Neil Shapiro q = strchr(++p, '?'); 1113299c2f1SGregory Neil Shapiro if (q == NULL) 1123299c2f1SGregory Neil Shapiro goto hse; 1133299c2f1SGregory Neil Shapiro 1143299c2f1SGregory Neil Shapiro *q = '\0'; 1153299c2f1SGregory Neil Shapiro c = *p & 0377; 1163299c2f1SGregory Neil Shapiro 1173299c2f1SGregory Neil Shapiro /* possibly macro conditional */ 1183299c2f1SGregory Neil Shapiro if (c == MACROEXPAND) 119c2aa98e2SPeter Wemm { 1203299c2f1SGregory Neil Shapiro /* catch ?$? */ 1213299c2f1SGregory Neil Shapiro if (*++p == '\0') 1223299c2f1SGregory Neil Shapiro { 1233299c2f1SGregory Neil Shapiro *q = '?'; 1243299c2f1SGregory Neil Shapiro goto hse; 1253299c2f1SGregory Neil Shapiro } 1263299c2f1SGregory Neil Shapiro 1273299c2f1SGregory Neil Shapiro mid = (u_char) *p++; 1283299c2f1SGregory Neil Shapiro 1293299c2f1SGregory Neil Shapiro /* catch ?$abc? */ 1303299c2f1SGregory Neil Shapiro if (*p != '\0') 1313299c2f1SGregory Neil Shapiro { 1323299c2f1SGregory Neil Shapiro *q = '?'; 1333299c2f1SGregory Neil Shapiro goto hse; 1343299c2f1SGregory Neil Shapiro } 1353299c2f1SGregory Neil Shapiro } 1363299c2f1SGregory Neil Shapiro else if (*p == '$') 1373299c2f1SGregory Neil Shapiro { 1383299c2f1SGregory Neil Shapiro /* catch ?$? */ 1393299c2f1SGregory Neil Shapiro if (*++p == '\0') 1403299c2f1SGregory Neil Shapiro { 1413299c2f1SGregory Neil Shapiro *q = '?'; 1423299c2f1SGregory Neil Shapiro goto hse; 1433299c2f1SGregory Neil Shapiro } 1443299c2f1SGregory Neil Shapiro 1453299c2f1SGregory Neil Shapiro mid = (u_char)macid(p, NULL); 1463299c2f1SGregory Neil Shapiro if (bitset(0200, mid)) 1473299c2f1SGregory Neil Shapiro p += strlen(macname(mid)) + 2; 1483299c2f1SGregory Neil Shapiro else 1493299c2f1SGregory Neil Shapiro p++; 1503299c2f1SGregory Neil Shapiro 1513299c2f1SGregory Neil Shapiro /* catch ?$abc? */ 1523299c2f1SGregory Neil Shapiro if (*p != '\0') 1533299c2f1SGregory Neil Shapiro { 1543299c2f1SGregory Neil Shapiro *q = '?'; 1553299c2f1SGregory Neil Shapiro goto hse; 1563299c2f1SGregory Neil Shapiro } 1573299c2f1SGregory Neil Shapiro 158c2aa98e2SPeter Wemm } 159c2aa98e2SPeter Wemm else 1603299c2f1SGregory Neil Shapiro { 1613299c2f1SGregory Neil Shapiro while (*p != '\0') 1623299c2f1SGregory Neil Shapiro { 1633299c2f1SGregory Neil Shapiro if (!isascii(*p)) 1643299c2f1SGregory Neil Shapiro { 1653299c2f1SGregory Neil Shapiro *q = '?'; 1663299c2f1SGregory Neil Shapiro goto hse; 1673299c2f1SGregory Neil Shapiro } 1683299c2f1SGregory Neil Shapiro 169c46d91b7SGregory Neil Shapiro setbitn(bitidx(*p), mopts); 170c2aa98e2SPeter Wemm cond = TRUE; 1713299c2f1SGregory Neil Shapiro p++; 1723299c2f1SGregory Neil Shapiro } 1733299c2f1SGregory Neil Shapiro } 1743299c2f1SGregory Neil Shapiro p = q + 1; 175c2aa98e2SPeter Wemm } 176c2aa98e2SPeter Wemm 177c2aa98e2SPeter Wemm /* find canonical name */ 178c2aa98e2SPeter Wemm fname = p; 179c2aa98e2SPeter Wemm while (isascii(*p) && isgraph(*p) && *p != ':') 180c2aa98e2SPeter Wemm p++; 181c2aa98e2SPeter Wemm fvalue = p; 182c2aa98e2SPeter Wemm while (isascii(*p) && isspace(*p)) 183c2aa98e2SPeter Wemm p++; 184c2aa98e2SPeter Wemm if (*p++ != ':' || fname == fvalue) 185c2aa98e2SPeter Wemm { 1863299c2f1SGregory Neil Shapiro hse: 1873299c2f1SGregory Neil Shapiro syserr("553 5.3.0 header syntax error, line \"%s\"", line); 188c2aa98e2SPeter Wemm return 0; 189c2aa98e2SPeter Wemm } 190c2aa98e2SPeter Wemm *fvalue = '\0'; 191c2aa98e2SPeter Wemm 192c2aa98e2SPeter Wemm /* strip field value on front */ 193e01d6f61SPeter Wemm if (*p == ' ') 194e01d6f61SPeter Wemm p++; 195e01d6f61SPeter Wemm fvalue = p; 196e01d6f61SPeter Wemm 197e01d6f61SPeter Wemm /* if the field is null, go ahead and use the default */ 198e01d6f61SPeter Wemm while (isascii(*p) && isspace(*p)) 199e01d6f61SPeter Wemm p++; 200e01d6f61SPeter Wemm if (*p == '\0') 201e01d6f61SPeter Wemm nullheader = TRUE; 202c2aa98e2SPeter Wemm 203c2aa98e2SPeter Wemm /* security scan: long field names are end-of-header */ 204c2aa98e2SPeter Wemm if (strlen(fname) > 100) 205c2aa98e2SPeter Wemm return H_EOH; 206c2aa98e2SPeter Wemm 207c2aa98e2SPeter Wemm /* check to see if it represents a ruleset call */ 2083299c2f1SGregory Neil Shapiro if (bitset(pflag, CHHDR_DEF)) 209c2aa98e2SPeter Wemm { 210c2aa98e2SPeter Wemm char hbuf[50]; 211c2aa98e2SPeter Wemm 212c2aa98e2SPeter Wemm (void) expand(fvalue, hbuf, sizeof hbuf, e); 213c2aa98e2SPeter Wemm for (p = hbuf; isascii(*p) && isspace(*p); ) 214c2aa98e2SPeter Wemm p++; 215c2aa98e2SPeter Wemm if ((*p++ & 0377) == CALLSUBR) 216c2aa98e2SPeter Wemm { 217c2aa98e2SPeter Wemm auto char *endp; 2183299c2f1SGregory Neil Shapiro bool strc; 219c2aa98e2SPeter Wemm 2203299c2f1SGregory Neil Shapiro strc = *p == '+'; /* strip comments? */ 2213299c2f1SGregory Neil Shapiro if (strc) 2223299c2f1SGregory Neil Shapiro ++p; 223c2aa98e2SPeter Wemm if (strtorwset(p, &endp, ST_ENTER) > 0) 224c2aa98e2SPeter Wemm { 225c2aa98e2SPeter Wemm *endp = '\0'; 226c2aa98e2SPeter Wemm s = stab(fname, ST_HEADER, ST_ENTER); 227c2aa98e2SPeter Wemm s->s_header.hi_ruleset = newstr(p); 2283299c2f1SGregory Neil Shapiro if (!strc) 2293299c2f1SGregory Neil Shapiro s->s_header.hi_flags |= H_STRIPCOMM; 230c2aa98e2SPeter Wemm } 231c2aa98e2SPeter Wemm return 0; 232c2aa98e2SPeter Wemm } 233c2aa98e2SPeter Wemm } 234c2aa98e2SPeter Wemm 235c2aa98e2SPeter Wemm /* see if it is a known type */ 236c2aa98e2SPeter Wemm s = stab(fname, ST_HEADER, ST_FIND); 237c2aa98e2SPeter Wemm if (s != NULL) 238c2aa98e2SPeter Wemm hi = &s->s_header; 239c2aa98e2SPeter Wemm else 240c2aa98e2SPeter Wemm hi = &NormalHeader; 241c2aa98e2SPeter Wemm 242c2aa98e2SPeter Wemm if (tTd(31, 9)) 243c2aa98e2SPeter Wemm { 244c2aa98e2SPeter Wemm if (s == NULL) 2453299c2f1SGregory Neil Shapiro dprintf("no header flags match\n"); 246c2aa98e2SPeter Wemm else 2473299c2f1SGregory Neil Shapiro dprintf("header match, flags=%lx, ruleset=%s\n", 248c2aa98e2SPeter Wemm hi->hi_flags, 249c2aa98e2SPeter Wemm hi->hi_ruleset == NULL ? "<NULL>" : hi->hi_ruleset); 250c2aa98e2SPeter Wemm } 251c2aa98e2SPeter Wemm 252c2aa98e2SPeter Wemm /* see if this is a resent message */ 2533299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly && 2543299c2f1SGregory Neil Shapiro bitset(H_RESENT, hi->hi_flags)) 255c2aa98e2SPeter Wemm e->e_flags |= EF_RESENT; 256c2aa98e2SPeter Wemm 257c2aa98e2SPeter Wemm /* if this is an Errors-To: header keep track of it now */ 2583299c2f1SGregory Neil Shapiro if (UseErrorsTo && !bitset(pflag, CHHDR_DEF) && !headeronly && 259c2aa98e2SPeter Wemm bitset(H_ERRORSTO, hi->hi_flags)) 260c2aa98e2SPeter Wemm (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e); 261c2aa98e2SPeter Wemm 262c2aa98e2SPeter Wemm /* if this means "end of header" quit now */ 263c2aa98e2SPeter Wemm if (!headeronly && bitset(H_EOH, hi->hi_flags)) 264c2aa98e2SPeter Wemm return hi->hi_flags; 265c2aa98e2SPeter Wemm 266c2aa98e2SPeter Wemm /* 267c2aa98e2SPeter Wemm ** Horrible hack to work around problem with Lotus Notes SMTP 268c2aa98e2SPeter Wemm ** mail gateway, which generates From: headers with newlines in 269c2aa98e2SPeter Wemm ** them and the <address> on the second line. Although this is 270c2aa98e2SPeter Wemm ** legal RFC 822, many MUAs don't handle this properly and thus 271c2aa98e2SPeter Wemm ** never find the actual address. 272c2aa98e2SPeter Wemm */ 273c2aa98e2SPeter Wemm 274c2aa98e2SPeter Wemm if (bitset(H_FROM, hi->hi_flags) && SingleLineFromHeader) 275c2aa98e2SPeter Wemm { 276c2aa98e2SPeter Wemm while ((p = strchr(fvalue, '\n')) != NULL) 277c2aa98e2SPeter Wemm *p = ' '; 278c2aa98e2SPeter Wemm } 279c2aa98e2SPeter Wemm 280c2aa98e2SPeter Wemm /* 281c2aa98e2SPeter Wemm ** If there is a check ruleset, verify it against the header. 282c2aa98e2SPeter Wemm */ 283c2aa98e2SPeter Wemm 2843299c2f1SGregory Neil Shapiro if (bitset(pflag, CHHDR_CHECK)) 2853299c2f1SGregory Neil Shapiro { 2863299c2f1SGregory Neil Shapiro bool stripcom = FALSE; 2873299c2f1SGregory Neil Shapiro char *rs; 2883299c2f1SGregory Neil Shapiro 2893299c2f1SGregory Neil Shapiro /* no ruleset? look for default */ 2903299c2f1SGregory Neil Shapiro rs = hi->hi_ruleset; 2913299c2f1SGregory Neil Shapiro if (rs == NULL) 2923299c2f1SGregory Neil Shapiro { 2933299c2f1SGregory Neil Shapiro s = stab("*", ST_HEADER, ST_FIND); 2943299c2f1SGregory Neil Shapiro if (s != NULL) 2953299c2f1SGregory Neil Shapiro { 2963299c2f1SGregory Neil Shapiro rs = (&s->s_header)->hi_ruleset; 2973299c2f1SGregory Neil Shapiro stripcom = bitset((&s->s_header)->hi_flags, 2983299c2f1SGregory Neil Shapiro H_STRIPCOMM); 2993299c2f1SGregory Neil Shapiro } 3003299c2f1SGregory Neil Shapiro } 3013299c2f1SGregory Neil Shapiro else 3023299c2f1SGregory Neil Shapiro stripcom = bitset(hi->hi_flags, H_STRIPCOMM); 3033299c2f1SGregory Neil Shapiro if (rs != NULL) 3043299c2f1SGregory Neil Shapiro { 3053299c2f1SGregory Neil Shapiro int l; 3063299c2f1SGregory Neil Shapiro char qval[MAXNAME]; 3073299c2f1SGregory Neil Shapiro char hlen[16]; 3083299c2f1SGregory Neil Shapiro char *sp, *dp; 3093299c2f1SGregory Neil Shapiro 3103299c2f1SGregory Neil Shapiro dp = qval; 3113299c2f1SGregory Neil Shapiro l = 0; 3123299c2f1SGregory Neil Shapiro dp[l++] = '"'; 3133299c2f1SGregory Neil Shapiro for (sp = fvalue; *sp != '\0' && l < MAXNAME - 2; sp++) 3143299c2f1SGregory Neil Shapiro { 3153299c2f1SGregory Neil Shapiro switch(*sp) 3163299c2f1SGregory Neil Shapiro { 3173299c2f1SGregory Neil Shapiro case '\011': /* ht */ 3183299c2f1SGregory Neil Shapiro case '\012': /* nl */ 3193299c2f1SGregory Neil Shapiro case '\013': /* vt */ 3203299c2f1SGregory Neil Shapiro case '\014': /* np */ 3213299c2f1SGregory Neil Shapiro case '\015': /* cr */ 3223299c2f1SGregory Neil Shapiro dp[l++] = ' '; 3233299c2f1SGregory Neil Shapiro break; 3243299c2f1SGregory Neil Shapiro case '"': 3253299c2f1SGregory Neil Shapiro dp[l++] = '\\'; 3263299c2f1SGregory Neil Shapiro /* FALLTHROUGH */ 3273299c2f1SGregory Neil Shapiro default: 3283299c2f1SGregory Neil Shapiro dp[l++] = *sp; 3293299c2f1SGregory Neil Shapiro break; 3303299c2f1SGregory Neil Shapiro } 3313299c2f1SGregory Neil Shapiro } 3323299c2f1SGregory Neil Shapiro dp[l++] = '"'; 3333299c2f1SGregory Neil Shapiro dp[l++] = '\0'; 3343299c2f1SGregory Neil Shapiro l = strlen(fvalue); 3353299c2f1SGregory Neil Shapiro snprintf(hlen, sizeof hlen, "%d", l); 3363299c2f1SGregory Neil Shapiro define(macid("{hdrlen}", NULL), newstr(hlen), e); 3373299c2f1SGregory Neil Shapiro if (l >= MAXNAME) 3383299c2f1SGregory Neil Shapiro { 3393299c2f1SGregory Neil Shapiro if (LogLevel > 9) 3403299c2f1SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id, 3413299c2f1SGregory Neil Shapiro "Warning: truncated header '%s' before check with '%s' len=%d max=%d", 3423299c2f1SGregory Neil Shapiro fname, rs, l, MAXNAME); 3433299c2f1SGregory Neil Shapiro } 3443299c2f1SGregory Neil Shapiro if ((sp = macvalue(macid("{currHeader}", NULL), e)) != 3453299c2f1SGregory Neil Shapiro NULL) 3463299c2f1SGregory Neil Shapiro free(sp); 3473299c2f1SGregory Neil Shapiro define(macid("{currHeader}", NULL), newstr(qval), e); 3483299c2f1SGregory Neil Shapiro define(macid("{hdr_name}", NULL), newstr(fname), e); 349c46d91b7SGregory Neil Shapiro (void) rscheck(rs, fvalue, NULL, e, stripcom, TRUE, 4, 350c46d91b7SGregory Neil Shapiro NULL); 3513299c2f1SGregory Neil Shapiro } 3523299c2f1SGregory Neil Shapiro } 353c2aa98e2SPeter Wemm 354c2aa98e2SPeter Wemm /* 355c2aa98e2SPeter Wemm ** Drop explicit From: if same as what we would generate. 356c2aa98e2SPeter Wemm ** This is to make MH (which doesn't always give a full name) 357c2aa98e2SPeter Wemm ** insert the full name information in all circumstances. 358c2aa98e2SPeter Wemm */ 359c2aa98e2SPeter Wemm 3603299c2f1SGregory Neil Shapiro dropfrom = FALSE; 361c2aa98e2SPeter Wemm p = "resent-from"; 362c2aa98e2SPeter Wemm if (!bitset(EF_RESENT, e->e_flags)) 363c2aa98e2SPeter Wemm p += 7; 3643299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly && 3653299c2f1SGregory Neil Shapiro !bitset(EF_QUEUERUN, e->e_flags) && strcasecmp(fname, p) == 0) 366c2aa98e2SPeter Wemm { 367c2aa98e2SPeter Wemm if (tTd(31, 2)) 368c2aa98e2SPeter Wemm { 3693299c2f1SGregory Neil Shapiro dprintf("comparing header from (%s) against default (%s or %s)\n", 370c2aa98e2SPeter Wemm fvalue, e->e_from.q_paddr, e->e_from.q_user); 371c2aa98e2SPeter Wemm } 372c2aa98e2SPeter Wemm if (e->e_from.q_paddr != NULL && 3733299c2f1SGregory Neil Shapiro e->e_from.q_mailer != NULL && 3743299c2f1SGregory Neil Shapiro bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) && 375c2aa98e2SPeter Wemm (strcmp(fvalue, e->e_from.q_paddr) == 0 || 376c2aa98e2SPeter Wemm strcmp(fvalue, e->e_from.q_user) == 0)) 3773299c2f1SGregory Neil Shapiro dropfrom = TRUE; 378c2aa98e2SPeter Wemm } 379c2aa98e2SPeter Wemm 380c2aa98e2SPeter Wemm /* delete default value for this header */ 381c2aa98e2SPeter Wemm for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link) 382c2aa98e2SPeter Wemm { 383c2aa98e2SPeter Wemm if (strcasecmp(fname, h->h_field) == 0 && 3843299c2f1SGregory Neil Shapiro !bitset(H_USER, h->h_flags) && 385c2aa98e2SPeter Wemm !bitset(H_FORCE, h->h_flags)) 386c2aa98e2SPeter Wemm { 387e01d6f61SPeter Wemm if (nullheader) 388e01d6f61SPeter Wemm { 389e01d6f61SPeter Wemm /* user-supplied value was null */ 390e01d6f61SPeter Wemm return 0; 391e01d6f61SPeter Wemm } 3923299c2f1SGregory Neil Shapiro if (dropfrom) 3933299c2f1SGregory Neil Shapiro { 3943299c2f1SGregory Neil Shapiro /* make this look like the user entered it */ 3953299c2f1SGregory Neil Shapiro h->h_flags |= H_USER; 3963299c2f1SGregory Neil Shapiro return hi->hi_flags; 3973299c2f1SGregory Neil Shapiro } 398c2aa98e2SPeter Wemm h->h_value = NULL; 399c2aa98e2SPeter Wemm if (!cond) 400c2aa98e2SPeter Wemm { 401c2aa98e2SPeter Wemm /* copy conditions from default case */ 4023299c2f1SGregory Neil Shapiro memmove((char *)mopts, (char *)h->h_mflags, 403c2aa98e2SPeter Wemm sizeof mopts); 404c2aa98e2SPeter Wemm } 4053299c2f1SGregory Neil Shapiro h->h_macro = mid; 406c2aa98e2SPeter Wemm } 407c2aa98e2SPeter Wemm } 408c2aa98e2SPeter Wemm 409c2aa98e2SPeter Wemm /* create a new node */ 410c2aa98e2SPeter Wemm h = (HDR *) xalloc(sizeof *h); 411c2aa98e2SPeter Wemm h->h_field = newstr(fname); 412c2aa98e2SPeter Wemm h->h_value = newstr(fvalue); 413c2aa98e2SPeter Wemm h->h_link = NULL; 4143299c2f1SGregory Neil Shapiro memmove((char *) h->h_mflags, (char *) mopts, sizeof mopts); 4153299c2f1SGregory Neil Shapiro h->h_macro = mid; 416c2aa98e2SPeter Wemm *hp = h; 417c2aa98e2SPeter Wemm h->h_flags = hi->hi_flags; 418d995d2baSGregory Neil Shapiro if (bitset(pflag, CHHDR_USER) || bitset(pflag, CHHDR_QUEUE)) 4193299c2f1SGregory Neil Shapiro h->h_flags |= H_USER; 420c2aa98e2SPeter Wemm 421c2aa98e2SPeter Wemm /* strip EOH flag if parsing MIME headers */ 422c2aa98e2SPeter Wemm if (headeronly) 423c2aa98e2SPeter Wemm h->h_flags &= ~H_EOH; 4243299c2f1SGregory Neil Shapiro if (bitset(pflag, CHHDR_DEF)) 425c2aa98e2SPeter Wemm h->h_flags |= H_DEFAULT; 4263299c2f1SGregory Neil Shapiro if (cond || mid != '\0') 427c2aa98e2SPeter Wemm h->h_flags |= H_CHECK; 428c2aa98e2SPeter Wemm 429c2aa98e2SPeter Wemm /* hack to see if this is a new format message */ 4303299c2f1SGregory Neil Shapiro if (!bitset(pflag, CHHDR_DEF) && !headeronly && 4313299c2f1SGregory Neil Shapiro bitset(H_RCPT|H_FROM, h->h_flags) && 432c2aa98e2SPeter Wemm (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || 433c2aa98e2SPeter Wemm strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) 434c2aa98e2SPeter Wemm { 435c2aa98e2SPeter Wemm e->e_flags &= ~EF_OLDSTYLE; 436c2aa98e2SPeter Wemm } 437c2aa98e2SPeter Wemm 438c2aa98e2SPeter Wemm return h->h_flags; 439c2aa98e2SPeter Wemm } 440c2aa98e2SPeter Wemm /* 441c2aa98e2SPeter Wemm ** ADDHEADER -- add a header entry to the end of the queue. 442c2aa98e2SPeter Wemm ** 443c2aa98e2SPeter Wemm ** This bypasses the special checking of chompheader. 444c2aa98e2SPeter Wemm ** 445c2aa98e2SPeter Wemm ** Parameters: 446c2aa98e2SPeter Wemm ** field -- the name of the header field. 447c2aa98e2SPeter Wemm ** value -- the value of the field. 4483299c2f1SGregory Neil Shapiro ** flags -- flags to add to h_flags. 4493299c2f1SGregory Neil Shapiro ** hdrlist -- an indirect pointer to the header structure list. 450c2aa98e2SPeter Wemm ** 451c2aa98e2SPeter Wemm ** Returns: 452c2aa98e2SPeter Wemm ** none. 453c2aa98e2SPeter Wemm ** 454c2aa98e2SPeter Wemm ** Side Effects: 455c2aa98e2SPeter Wemm ** adds the field on the list of headers for this envelope. 456c2aa98e2SPeter Wemm */ 457c2aa98e2SPeter Wemm 458c2aa98e2SPeter Wemm void 4593299c2f1SGregory Neil Shapiro addheader(field, value, flags, hdrlist) 460c2aa98e2SPeter Wemm char *field; 461c2aa98e2SPeter Wemm char *value; 4623299c2f1SGregory Neil Shapiro int flags; 463c2aa98e2SPeter Wemm HDR **hdrlist; 464c2aa98e2SPeter Wemm { 465c2aa98e2SPeter Wemm register HDR *h; 466c2aa98e2SPeter Wemm STAB *s; 467c2aa98e2SPeter Wemm HDR **hp; 468c2aa98e2SPeter Wemm 469c2aa98e2SPeter Wemm /* find info struct */ 470c2aa98e2SPeter Wemm s = stab(field, ST_HEADER, ST_FIND); 471c2aa98e2SPeter Wemm 472c2aa98e2SPeter Wemm /* find current place in list -- keep back pointer? */ 473c2aa98e2SPeter Wemm for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link) 474c2aa98e2SPeter Wemm { 475c2aa98e2SPeter Wemm if (strcasecmp(field, h->h_field) == 0) 476c2aa98e2SPeter Wemm break; 477c2aa98e2SPeter Wemm } 478c2aa98e2SPeter Wemm 479c2aa98e2SPeter Wemm /* allocate space for new header */ 480c2aa98e2SPeter Wemm h = (HDR *) xalloc(sizeof *h); 481c2aa98e2SPeter Wemm h->h_field = field; 482c2aa98e2SPeter Wemm h->h_value = newstr(value); 483c2aa98e2SPeter Wemm h->h_link = *hp; 4843299c2f1SGregory Neil Shapiro h->h_flags = flags; 485c2aa98e2SPeter Wemm if (s != NULL) 486c2aa98e2SPeter Wemm h->h_flags |= s->s_header.hi_flags; 487c2aa98e2SPeter Wemm clrbitmap(h->h_mflags); 4883299c2f1SGregory Neil Shapiro h->h_macro = '\0'; 489c2aa98e2SPeter Wemm *hp = h; 490c2aa98e2SPeter Wemm } 491c2aa98e2SPeter Wemm /* 492c2aa98e2SPeter Wemm ** HVALUE -- return value of a header. 493c2aa98e2SPeter Wemm ** 494c2aa98e2SPeter Wemm ** Only "real" fields (i.e., ones that have not been supplied 495c2aa98e2SPeter Wemm ** as a default) are used. 496c2aa98e2SPeter Wemm ** 497c2aa98e2SPeter Wemm ** Parameters: 498c2aa98e2SPeter Wemm ** field -- the field name. 499c2aa98e2SPeter Wemm ** header -- the header list. 500c2aa98e2SPeter Wemm ** 501c2aa98e2SPeter Wemm ** Returns: 502c2aa98e2SPeter Wemm ** pointer to the value part. 503c2aa98e2SPeter Wemm ** NULL if not found. 504c2aa98e2SPeter Wemm ** 505c2aa98e2SPeter Wemm ** Side Effects: 506c2aa98e2SPeter Wemm ** none. 507c2aa98e2SPeter Wemm */ 508c2aa98e2SPeter Wemm 509c2aa98e2SPeter Wemm char * 510c2aa98e2SPeter Wemm hvalue(field, header) 511c2aa98e2SPeter Wemm char *field; 512c2aa98e2SPeter Wemm HDR *header; 513c2aa98e2SPeter Wemm { 514c2aa98e2SPeter Wemm register HDR *h; 515c2aa98e2SPeter Wemm 516c2aa98e2SPeter Wemm for (h = header; h != NULL; h = h->h_link) 517c2aa98e2SPeter Wemm { 518c2aa98e2SPeter Wemm if (!bitset(H_DEFAULT, h->h_flags) && 519c2aa98e2SPeter Wemm strcasecmp(h->h_field, field) == 0) 5203299c2f1SGregory Neil Shapiro return h->h_value; 521c2aa98e2SPeter Wemm } 5223299c2f1SGregory Neil Shapiro return NULL; 523c2aa98e2SPeter Wemm } 524c2aa98e2SPeter Wemm /* 525c2aa98e2SPeter Wemm ** ISHEADER -- predicate telling if argument is a header. 526c2aa98e2SPeter Wemm ** 527c2aa98e2SPeter Wemm ** A line is a header if it has a single word followed by 528c2aa98e2SPeter Wemm ** optional white space followed by a colon. 529c2aa98e2SPeter Wemm ** 530c2aa98e2SPeter Wemm ** Header fields beginning with two dashes, although technically 531c2aa98e2SPeter Wemm ** permitted by RFC822, are automatically rejected in order 532c2aa98e2SPeter Wemm ** to make MIME work out. Without this we could have a technically 533c2aa98e2SPeter Wemm ** legal header such as ``--"foo:bar"'' that would also be a legal 534c2aa98e2SPeter Wemm ** MIME separator. 535c2aa98e2SPeter Wemm ** 536c2aa98e2SPeter Wemm ** Parameters: 537c2aa98e2SPeter Wemm ** h -- string to check for possible headerness. 538c2aa98e2SPeter Wemm ** 539c2aa98e2SPeter Wemm ** Returns: 540c2aa98e2SPeter Wemm ** TRUE if h is a header. 541c2aa98e2SPeter Wemm ** FALSE otherwise. 542c2aa98e2SPeter Wemm ** 543c2aa98e2SPeter Wemm ** Side Effects: 544c2aa98e2SPeter Wemm ** none. 545c2aa98e2SPeter Wemm */ 546c2aa98e2SPeter Wemm 547c2aa98e2SPeter Wemm bool 548c2aa98e2SPeter Wemm isheader(h) 549c2aa98e2SPeter Wemm char *h; 550c2aa98e2SPeter Wemm { 551c2aa98e2SPeter Wemm register char *s = h; 552c2aa98e2SPeter Wemm 553c2aa98e2SPeter Wemm if (s[0] == '-' && s[1] == '-') 554c2aa98e2SPeter Wemm return FALSE; 555c2aa98e2SPeter Wemm 556c2aa98e2SPeter Wemm while (*s > ' ' && *s != ':' && *s != '\0') 557c2aa98e2SPeter Wemm s++; 558c2aa98e2SPeter Wemm 559c2aa98e2SPeter Wemm if (h == s) 560c2aa98e2SPeter Wemm return FALSE; 561c2aa98e2SPeter Wemm 562c2aa98e2SPeter Wemm /* following technically violates RFC822 */ 563c2aa98e2SPeter Wemm while (isascii(*s) && isspace(*s)) 564c2aa98e2SPeter Wemm s++; 565c2aa98e2SPeter Wemm 566c2aa98e2SPeter Wemm return (*s == ':'); 567c2aa98e2SPeter Wemm } 568c2aa98e2SPeter Wemm /* 569c2aa98e2SPeter Wemm ** EATHEADER -- run through the stored header and extract info. 570c2aa98e2SPeter Wemm ** 571c2aa98e2SPeter Wemm ** Parameters: 572c2aa98e2SPeter Wemm ** e -- the envelope to process. 573c2aa98e2SPeter Wemm ** full -- if set, do full processing (e.g., compute 574c2aa98e2SPeter Wemm ** message priority). This should not be set 575c2aa98e2SPeter Wemm ** when reading a queue file because some info 576c2aa98e2SPeter Wemm ** needed to compute the priority is wrong. 577c2aa98e2SPeter Wemm ** 578c2aa98e2SPeter Wemm ** Returns: 579c2aa98e2SPeter Wemm ** none. 580c2aa98e2SPeter Wemm ** 581c2aa98e2SPeter Wemm ** Side Effects: 582c2aa98e2SPeter Wemm ** Sets a bunch of global variables from information 583c2aa98e2SPeter Wemm ** in the collected header. 584c2aa98e2SPeter Wemm ** Aborts the message if the hop count is exceeded. 585c2aa98e2SPeter Wemm */ 586c2aa98e2SPeter Wemm 587c2aa98e2SPeter Wemm void 588c2aa98e2SPeter Wemm eatheader(e, full) 589c2aa98e2SPeter Wemm register ENVELOPE *e; 590c2aa98e2SPeter Wemm bool full; 591c2aa98e2SPeter Wemm { 592c2aa98e2SPeter Wemm register HDR *h; 593c2aa98e2SPeter Wemm register char *p; 594c2aa98e2SPeter Wemm int hopcnt = 0; 595c2aa98e2SPeter Wemm char *msgid; 596c2aa98e2SPeter Wemm char buf[MAXLINE]; 597c2aa98e2SPeter Wemm 598c2aa98e2SPeter Wemm /* 599c2aa98e2SPeter Wemm ** Set up macros for possible expansion in headers. 600c2aa98e2SPeter Wemm */ 601c2aa98e2SPeter Wemm 602c2aa98e2SPeter Wemm define('f', e->e_sender, e); 603c2aa98e2SPeter Wemm define('g', e->e_sender, e); 604c2aa98e2SPeter Wemm if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0') 605c2aa98e2SPeter Wemm define('u', e->e_origrcpt, e); 606c2aa98e2SPeter Wemm else 607c2aa98e2SPeter Wemm define('u', NULL, e); 608c2aa98e2SPeter Wemm 609c2aa98e2SPeter Wemm /* full name of from person */ 610c2aa98e2SPeter Wemm p = hvalue("full-name", e->e_header); 611c2aa98e2SPeter Wemm if (p != NULL) 612c2aa98e2SPeter Wemm { 613c2aa98e2SPeter Wemm if (!rfc822_string(p)) 614c2aa98e2SPeter Wemm { 615c2aa98e2SPeter Wemm /* 616c2aa98e2SPeter Wemm ** Quote a full name with special characters 617c2aa98e2SPeter Wemm ** as a comment so crackaddr() doesn't destroy 618c2aa98e2SPeter Wemm ** the name portion of the address. 619c2aa98e2SPeter Wemm */ 620c2aa98e2SPeter Wemm p = addquotes(p); 621c2aa98e2SPeter Wemm } 622c2aa98e2SPeter Wemm define('x', p, e); 623c2aa98e2SPeter Wemm } 624c2aa98e2SPeter Wemm 625c2aa98e2SPeter Wemm if (tTd(32, 1)) 6263299c2f1SGregory Neil Shapiro dprintf("----- collected header -----\n"); 627c2aa98e2SPeter Wemm msgid = NULL; 628c2aa98e2SPeter Wemm for (h = e->e_header; h != NULL; h = h->h_link) 629c2aa98e2SPeter Wemm { 630c2aa98e2SPeter Wemm if (tTd(32, 1)) 6313299c2f1SGregory Neil Shapiro dprintf("%s: ", h->h_field); 632c2aa98e2SPeter Wemm if (h->h_value == NULL) 633c2aa98e2SPeter Wemm { 634c2aa98e2SPeter Wemm if (tTd(32, 1)) 6353299c2f1SGregory Neil Shapiro dprintf("<NULL>\n"); 636c2aa98e2SPeter Wemm continue; 637c2aa98e2SPeter Wemm } 638c2aa98e2SPeter Wemm 639c2aa98e2SPeter Wemm /* do early binding */ 6403299c2f1SGregory Neil Shapiro if (bitset(H_DEFAULT, h->h_flags) && 6413299c2f1SGregory Neil Shapiro !bitset(H_BINDLATE, h->h_flags)) 642c2aa98e2SPeter Wemm { 643c2aa98e2SPeter Wemm if (tTd(32, 1)) 644c2aa98e2SPeter Wemm { 6453299c2f1SGregory Neil Shapiro dprintf("("); 646c2aa98e2SPeter Wemm xputs(h->h_value); 6473299c2f1SGregory Neil Shapiro dprintf(") "); 648c2aa98e2SPeter Wemm } 649c2aa98e2SPeter Wemm expand(h->h_value, buf, sizeof buf, e); 650c2aa98e2SPeter Wemm if (buf[0] != '\0') 651c2aa98e2SPeter Wemm { 652c2aa98e2SPeter Wemm if (bitset(H_FROM, h->h_flags)) 653c2aa98e2SPeter Wemm expand(crackaddr(buf), buf, sizeof buf, e); 654c2aa98e2SPeter Wemm h->h_value = newstr(buf); 655c2aa98e2SPeter Wemm h->h_flags &= ~H_DEFAULT; 656c2aa98e2SPeter Wemm } 657c2aa98e2SPeter Wemm } 658c2aa98e2SPeter Wemm 659c2aa98e2SPeter Wemm if (tTd(32, 1)) 660c2aa98e2SPeter Wemm { 661c2aa98e2SPeter Wemm xputs(h->h_value); 6623299c2f1SGregory Neil Shapiro dprintf("\n"); 663c2aa98e2SPeter Wemm } 664c2aa98e2SPeter Wemm 665c2aa98e2SPeter Wemm /* count the number of times it has been processed */ 666c2aa98e2SPeter Wemm if (bitset(H_TRACE, h->h_flags)) 667c2aa98e2SPeter Wemm hopcnt++; 668c2aa98e2SPeter Wemm 669c2aa98e2SPeter Wemm /* send to this person if we so desire */ 670c2aa98e2SPeter Wemm if (GrabTo && bitset(H_RCPT, h->h_flags) && 671c2aa98e2SPeter Wemm !bitset(H_DEFAULT, h->h_flags) && 672c2aa98e2SPeter Wemm (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags))) 673c2aa98e2SPeter Wemm { 674c2aa98e2SPeter Wemm #if 0 675c2aa98e2SPeter Wemm int saveflags = e->e_flags; 6763299c2f1SGregory Neil Shapiro #endif /* 0 */ 677c2aa98e2SPeter Wemm 678c2aa98e2SPeter Wemm (void) sendtolist(h->h_value, NULLADDR, 679c2aa98e2SPeter Wemm &e->e_sendqueue, 0, e); 680c2aa98e2SPeter Wemm 681c2aa98e2SPeter Wemm #if 0 682c2aa98e2SPeter Wemm /* 683c2aa98e2SPeter Wemm ** Change functionality so a fatal error on an 684c2aa98e2SPeter Wemm ** address doesn't affect the entire envelope. 685c2aa98e2SPeter Wemm */ 686c2aa98e2SPeter Wemm 687c2aa98e2SPeter Wemm /* delete fatal errors generated by this address */ 688c2aa98e2SPeter Wemm if (!bitset(EF_FATALERRS, saveflags)) 689c2aa98e2SPeter Wemm e->e_flags &= ~EF_FATALERRS; 6903299c2f1SGregory Neil Shapiro #endif /* 0 */ 691c2aa98e2SPeter Wemm } 692c2aa98e2SPeter Wemm 693c2aa98e2SPeter Wemm /* save the message-id for logging */ 694c2aa98e2SPeter Wemm p = "resent-message-id"; 695c2aa98e2SPeter Wemm if (!bitset(EF_RESENT, e->e_flags)) 696c2aa98e2SPeter Wemm p += 7; 697c2aa98e2SPeter Wemm if (strcasecmp(h->h_field, p) == 0) 698c2aa98e2SPeter Wemm { 699c2aa98e2SPeter Wemm msgid = h->h_value; 700c2aa98e2SPeter Wemm while (isascii(*msgid) && isspace(*msgid)) 701c2aa98e2SPeter Wemm msgid++; 702c2aa98e2SPeter Wemm } 703c2aa98e2SPeter Wemm } 704c2aa98e2SPeter Wemm if (tTd(32, 1)) 7053299c2f1SGregory Neil Shapiro dprintf("----------------------------\n"); 706c2aa98e2SPeter Wemm 707c2aa98e2SPeter Wemm /* if we are just verifying (that is, sendmail -t -bv), drop out now */ 708c2aa98e2SPeter Wemm if (OpMode == MD_VERIFY) 709c2aa98e2SPeter Wemm return; 710c2aa98e2SPeter Wemm 711c2aa98e2SPeter Wemm /* store hop count */ 712c2aa98e2SPeter Wemm if (hopcnt > e->e_hopcount) 713c2aa98e2SPeter Wemm e->e_hopcount = hopcnt; 714c2aa98e2SPeter Wemm 715c2aa98e2SPeter Wemm /* message priority */ 716c2aa98e2SPeter Wemm p = hvalue("precedence", e->e_header); 717c2aa98e2SPeter Wemm if (p != NULL) 718c2aa98e2SPeter Wemm e->e_class = priencode(p); 719c2aa98e2SPeter Wemm if (e->e_class < 0) 720c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_NONURGENT; 721c2aa98e2SPeter Wemm else if (e->e_class > 0) 722c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_URGENT; 723c2aa98e2SPeter Wemm if (full) 724c2aa98e2SPeter Wemm { 725c2aa98e2SPeter Wemm e->e_msgpriority = e->e_msgsize 726c2aa98e2SPeter Wemm - e->e_class * WkClassFact 727c2aa98e2SPeter Wemm + e->e_nrcpts * WkRecipFact; 728c2aa98e2SPeter Wemm } 729c2aa98e2SPeter Wemm 730c2aa98e2SPeter Wemm /* message timeout priority */ 731c2aa98e2SPeter Wemm p = hvalue("priority", e->e_header); 732c2aa98e2SPeter Wemm if (p != NULL) 733c2aa98e2SPeter Wemm { 734c2aa98e2SPeter Wemm /* (this should be in the configuration file) */ 735c2aa98e2SPeter Wemm if (strcasecmp(p, "urgent") == 0) 736c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_URGENT; 737c2aa98e2SPeter Wemm else if (strcasecmp(p, "normal") == 0) 738c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_NORMAL; 739c2aa98e2SPeter Wemm else if (strcasecmp(p, "non-urgent") == 0) 740c2aa98e2SPeter Wemm e->e_timeoutclass = TOC_NONURGENT; 741c2aa98e2SPeter Wemm } 742c2aa98e2SPeter Wemm 743c2aa98e2SPeter Wemm /* date message originated */ 744c2aa98e2SPeter Wemm p = hvalue("posted-date", e->e_header); 745c2aa98e2SPeter Wemm if (p == NULL) 746c2aa98e2SPeter Wemm p = hvalue("date", e->e_header); 747c2aa98e2SPeter Wemm if (p != NULL) 748c2aa98e2SPeter Wemm define('a', p, e); 749c2aa98e2SPeter Wemm 750c2aa98e2SPeter Wemm /* check to see if this is a MIME message */ 751c2aa98e2SPeter Wemm if ((e->e_bodytype != NULL && 752c2aa98e2SPeter Wemm strcasecmp(e->e_bodytype, "8BITMIME") == 0) || 753c2aa98e2SPeter Wemm hvalue("MIME-Version", e->e_header) != NULL) 754c2aa98e2SPeter Wemm { 755c2aa98e2SPeter Wemm e->e_flags |= EF_IS_MIME; 756c2aa98e2SPeter Wemm if (HasEightBits) 757c2aa98e2SPeter Wemm e->e_bodytype = "8BITMIME"; 758c2aa98e2SPeter Wemm } 759c2aa98e2SPeter Wemm else if ((p = hvalue("Content-Type", e->e_header)) != NULL) 760c2aa98e2SPeter Wemm { 761c2aa98e2SPeter Wemm /* this may be an RFC 1049 message */ 762c2aa98e2SPeter Wemm p = strpbrk(p, ";/"); 763c2aa98e2SPeter Wemm if (p == NULL || *p == ';') 764c2aa98e2SPeter Wemm { 765c2aa98e2SPeter Wemm /* yep, it is */ 766c2aa98e2SPeter Wemm e->e_flags |= EF_DONT_MIME; 767c2aa98e2SPeter Wemm } 768c2aa98e2SPeter Wemm } 769c2aa98e2SPeter Wemm 770c2aa98e2SPeter Wemm /* 771c2aa98e2SPeter Wemm ** From person in antiquated ARPANET mode 772c2aa98e2SPeter Wemm ** required by UK Grey Book e-mail gateways (sigh) 773c2aa98e2SPeter Wemm */ 774c2aa98e2SPeter Wemm 775c2aa98e2SPeter Wemm if (OpMode == MD_ARPAFTP) 776c2aa98e2SPeter Wemm { 777c2aa98e2SPeter Wemm register struct hdrinfo *hi; 778c2aa98e2SPeter Wemm 779c2aa98e2SPeter Wemm for (hi = HdrInfo; hi->hi_field != NULL; hi++) 780c2aa98e2SPeter Wemm { 781c2aa98e2SPeter Wemm if (bitset(H_FROM, hi->hi_flags) && 782c2aa98e2SPeter Wemm (!bitset(H_RESENT, hi->hi_flags) || 783c2aa98e2SPeter Wemm bitset(EF_RESENT, e->e_flags)) && 784c2aa98e2SPeter Wemm (p = hvalue(hi->hi_field, e->e_header)) != NULL) 785c2aa98e2SPeter Wemm break; 786c2aa98e2SPeter Wemm } 787c2aa98e2SPeter Wemm if (hi->hi_field != NULL) 788c2aa98e2SPeter Wemm { 789c2aa98e2SPeter Wemm if (tTd(32, 2)) 7903299c2f1SGregory Neil Shapiro dprintf("eatheader: setsender(*%s == %s)\n", 791c2aa98e2SPeter Wemm hi->hi_field, p); 792c2aa98e2SPeter Wemm setsender(p, e, NULL, '\0', TRUE); 793c2aa98e2SPeter Wemm } 794c2aa98e2SPeter Wemm } 795c2aa98e2SPeter Wemm 796c2aa98e2SPeter Wemm /* 797c2aa98e2SPeter Wemm ** Log collection information. 798c2aa98e2SPeter Wemm */ 799c2aa98e2SPeter Wemm 800c2aa98e2SPeter Wemm if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) 801c2aa98e2SPeter Wemm logsender(e, msgid); 802c2aa98e2SPeter Wemm e->e_flags &= ~EF_LOGSENDER; 803c2aa98e2SPeter Wemm } 804c2aa98e2SPeter Wemm /* 805c2aa98e2SPeter Wemm ** LOGSENDER -- log sender information 806c2aa98e2SPeter Wemm ** 807c2aa98e2SPeter Wemm ** Parameters: 808c2aa98e2SPeter Wemm ** e -- the envelope to log 809c2aa98e2SPeter Wemm ** msgid -- the message id 810c2aa98e2SPeter Wemm ** 811c2aa98e2SPeter Wemm ** Returns: 812c2aa98e2SPeter Wemm ** none 813c2aa98e2SPeter Wemm */ 814c2aa98e2SPeter Wemm 815c2aa98e2SPeter Wemm void 816c2aa98e2SPeter Wemm logsender(e, msgid) 817c2aa98e2SPeter Wemm register ENVELOPE *e; 818c2aa98e2SPeter Wemm char *msgid; 819c2aa98e2SPeter Wemm { 820c2aa98e2SPeter Wemm char *name; 821c2aa98e2SPeter Wemm register char *sbp; 822c2aa98e2SPeter Wemm register char *p; 823c2aa98e2SPeter Wemm int l; 824c2aa98e2SPeter Wemm char hbuf[MAXNAME + 1]; 825c2aa98e2SPeter Wemm char sbuf[MAXLINE + 1]; 826c2aa98e2SPeter Wemm char mbuf[MAXNAME + 1]; 827c2aa98e2SPeter Wemm 828c2aa98e2SPeter Wemm /* don't allow newlines in the message-id */ 829c2aa98e2SPeter Wemm if (msgid != NULL) 830c2aa98e2SPeter Wemm { 831c2aa98e2SPeter Wemm l = strlen(msgid); 832c2aa98e2SPeter Wemm if (l > sizeof mbuf - 1) 833c2aa98e2SPeter Wemm l = sizeof mbuf - 1; 8343299c2f1SGregory Neil Shapiro memmove(mbuf, msgid, l); 835c2aa98e2SPeter Wemm mbuf[l] = '\0'; 836c2aa98e2SPeter Wemm p = mbuf; 837c2aa98e2SPeter Wemm while ((p = strchr(p, '\n')) != NULL) 838c2aa98e2SPeter Wemm *p++ = ' '; 839c2aa98e2SPeter Wemm } 840c2aa98e2SPeter Wemm 841c2aa98e2SPeter Wemm if (bitset(EF_RESPONSE, e->e_flags)) 842c2aa98e2SPeter Wemm name = "[RESPONSE]"; 843c2aa98e2SPeter Wemm else if ((name = macvalue('_', e)) != NULL) 8443299c2f1SGregory Neil Shapiro /* EMPTY */ 845c2aa98e2SPeter Wemm ; 846c2aa98e2SPeter Wemm else if (RealHostName == NULL) 847c2aa98e2SPeter Wemm name = "localhost"; 848c2aa98e2SPeter Wemm else if (RealHostName[0] == '[') 849c2aa98e2SPeter Wemm name = RealHostName; 850c2aa98e2SPeter Wemm else 851c2aa98e2SPeter Wemm { 852c2aa98e2SPeter Wemm name = hbuf; 853c2aa98e2SPeter Wemm (void) snprintf(hbuf, sizeof hbuf, "%.80s", RealHostName); 854c2aa98e2SPeter Wemm if (RealHostAddr.sa.sa_family != 0) 855c2aa98e2SPeter Wemm { 856c2aa98e2SPeter Wemm p = &hbuf[strlen(hbuf)]; 857c2aa98e2SPeter Wemm (void) snprintf(p, SPACELEFT(hbuf, p), " (%.100s)", 858c2aa98e2SPeter Wemm anynet_ntoa(&RealHostAddr)); 859c2aa98e2SPeter Wemm } 860c2aa98e2SPeter Wemm } 861c2aa98e2SPeter Wemm 862c2aa98e2SPeter Wemm /* some versions of syslog only take 5 printf args */ 863c2aa98e2SPeter Wemm #if (SYSLOG_BUFSIZE) >= 256 864c2aa98e2SPeter Wemm sbp = sbuf; 865c2aa98e2SPeter Wemm snprintf(sbp, SPACELEFT(sbuf, sbp), 8663299c2f1SGregory Neil Shapiro "from=%.200s, size=%ld, class=%d, nrcpts=%d", 867c2aa98e2SPeter Wemm e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr, 8683299c2f1SGregory Neil Shapiro e->e_msgsize, e->e_class, e->e_nrcpts); 869c2aa98e2SPeter Wemm sbp += strlen(sbp); 870c2aa98e2SPeter Wemm if (msgid != NULL) 871c2aa98e2SPeter Wemm { 872c2aa98e2SPeter Wemm snprintf(sbp, SPACELEFT(sbuf, sbp), ", msgid=%.100s", mbuf); 873c2aa98e2SPeter Wemm sbp += strlen(sbp); 874c2aa98e2SPeter Wemm } 875c2aa98e2SPeter Wemm if (e->e_bodytype != NULL) 876c2aa98e2SPeter Wemm { 877c2aa98e2SPeter Wemm (void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", bodytype=%.20s", 878c2aa98e2SPeter Wemm e->e_bodytype); 879c2aa98e2SPeter Wemm sbp += strlen(sbp); 880c2aa98e2SPeter Wemm } 881c2aa98e2SPeter Wemm p = macvalue('r', e); 882c2aa98e2SPeter Wemm if (p != NULL) 8833299c2f1SGregory Neil Shapiro { 884c2aa98e2SPeter Wemm (void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", proto=%.20s", p); 8853299c2f1SGregory Neil Shapiro sbp += strlen(sbp); 8863299c2f1SGregory Neil Shapiro } 8873299c2f1SGregory Neil Shapiro p = macvalue(macid("{daemon_name}", NULL), e); 8883299c2f1SGregory Neil Shapiro if (p != NULL) 8893299c2f1SGregory Neil Shapiro { 8903299c2f1SGregory Neil Shapiro (void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", daemon=%.20s", p); 8913299c2f1SGregory Neil Shapiro sbp += strlen(sbp); 8923299c2f1SGregory Neil Shapiro } 8933299c2f1SGregory Neil Shapiro # if SASL 8943299c2f1SGregory Neil Shapiro p = macvalue(macid("{auth_type}", NULL), e); 8953299c2f1SGregory Neil Shapiro if (p != NULL) 8963299c2f1SGregory Neil Shapiro { 8973299c2f1SGregory Neil Shapiro (void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", mech=%.12s", p); 8983299c2f1SGregory Neil Shapiro sbp += strlen(sbp); 8993299c2f1SGregory Neil Shapiro } 9003299c2f1SGregory Neil Shapiro p = macvalue(macid("{auth_author}", NULL), e); 9013299c2f1SGregory Neil Shapiro if (p != NULL) 9023299c2f1SGregory Neil Shapiro { 9033299c2f1SGregory Neil Shapiro (void) snprintf(sbp, SPACELEFT(sbuf, sbp), ", auth=%.30s", p); 9043299c2f1SGregory Neil Shapiro sbp += strlen(sbp); 9053299c2f1SGregory Neil Shapiro } 9063299c2f1SGregory Neil Shapiro # endif /* SASL */ 907c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 908c2aa98e2SPeter Wemm "%.850s, relay=%.100s", 909c2aa98e2SPeter Wemm sbuf, name); 910c2aa98e2SPeter Wemm 9113299c2f1SGregory Neil Shapiro #else /* (SYSLOG_BUFSIZE) >= 256 */ 912c2aa98e2SPeter Wemm 913c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 914c2aa98e2SPeter Wemm "from=%s", 915c2aa98e2SPeter Wemm e->e_from.q_paddr == NULL ? "<NONE>" 916c2aa98e2SPeter Wemm : shortenstring(e->e_from.q_paddr, 83)); 917c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 9183299c2f1SGregory Neil Shapiro "size=%ld, class=%ld, nrcpts=%d", 9193299c2f1SGregory Neil Shapiro e->e_msgsize, e->e_class, e->e_nrcpts); 920c2aa98e2SPeter Wemm if (msgid != NULL) 921c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 922c2aa98e2SPeter Wemm "msgid=%s", 923c2aa98e2SPeter Wemm shortenstring(mbuf, 83)); 924c2aa98e2SPeter Wemm sbp = sbuf; 925c2aa98e2SPeter Wemm *sbp = '\0'; 926c2aa98e2SPeter Wemm if (e->e_bodytype != NULL) 927c2aa98e2SPeter Wemm { 928c2aa98e2SPeter Wemm snprintf(sbp, SPACELEFT(sbuf, sbp), "bodytype=%.20s, ", e->e_bodytype); 929c2aa98e2SPeter Wemm sbp += strlen(sbp); 930c2aa98e2SPeter Wemm } 931c2aa98e2SPeter Wemm p = macvalue('r', e); 932c2aa98e2SPeter Wemm if (p != NULL) 933c2aa98e2SPeter Wemm { 934c2aa98e2SPeter Wemm snprintf(sbp, SPACELEFT(sbuf, sbp), "proto=%.20s, ", p); 935c2aa98e2SPeter Wemm sbp += strlen(sbp); 936c2aa98e2SPeter Wemm } 937c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id, 938c2aa98e2SPeter Wemm "%.400srelay=%.100s", sbuf, name); 9393299c2f1SGregory Neil Shapiro #endif /* (SYSLOG_BUFSIZE) >= 256 */ 940c2aa98e2SPeter Wemm } 941c2aa98e2SPeter Wemm /* 942c2aa98e2SPeter Wemm ** PRIENCODE -- encode external priority names into internal values. 943c2aa98e2SPeter Wemm ** 944c2aa98e2SPeter Wemm ** Parameters: 945c2aa98e2SPeter Wemm ** p -- priority in ascii. 946c2aa98e2SPeter Wemm ** 947c2aa98e2SPeter Wemm ** Returns: 948c2aa98e2SPeter Wemm ** priority as a numeric level. 949c2aa98e2SPeter Wemm ** 950c2aa98e2SPeter Wemm ** Side Effects: 951c2aa98e2SPeter Wemm ** none. 952c2aa98e2SPeter Wemm */ 953c2aa98e2SPeter Wemm 9543299c2f1SGregory Neil Shapiro static int 955c2aa98e2SPeter Wemm priencode(p) 956c2aa98e2SPeter Wemm char *p; 957c2aa98e2SPeter Wemm { 958c2aa98e2SPeter Wemm register int i; 959c2aa98e2SPeter Wemm 960c2aa98e2SPeter Wemm for (i = 0; i < NumPriorities; i++) 961c2aa98e2SPeter Wemm { 9623299c2f1SGregory Neil Shapiro if (strcasecmp(p, Priorities[i].pri_name) == 0) 9633299c2f1SGregory Neil Shapiro return Priorities[i].pri_val; 964c2aa98e2SPeter Wemm } 965c2aa98e2SPeter Wemm 966c2aa98e2SPeter Wemm /* unknown priority */ 9673299c2f1SGregory Neil Shapiro return 0; 968c2aa98e2SPeter Wemm } 969c2aa98e2SPeter Wemm /* 970c2aa98e2SPeter Wemm ** CRACKADDR -- parse an address and turn it into a macro 971c2aa98e2SPeter Wemm ** 972c2aa98e2SPeter Wemm ** This doesn't actually parse the address -- it just extracts 973c2aa98e2SPeter Wemm ** it and replaces it with "$g". The parse is totally ad hoc 974c2aa98e2SPeter Wemm ** and isn't even guaranteed to leave something syntactically 975c2aa98e2SPeter Wemm ** identical to what it started with. However, it does leave 976c2aa98e2SPeter Wemm ** something semantically identical. 977c2aa98e2SPeter Wemm ** 978c2aa98e2SPeter Wemm ** This algorithm has been cleaned up to handle a wider range 979c2aa98e2SPeter Wemm ** of cases -- notably quoted and backslash escaped strings. 980c2aa98e2SPeter Wemm ** This modification makes it substantially better at preserving 981c2aa98e2SPeter Wemm ** the original syntax. 982c2aa98e2SPeter Wemm ** 983c2aa98e2SPeter Wemm ** Parameters: 984c2aa98e2SPeter Wemm ** addr -- the address to be cracked. 985c2aa98e2SPeter Wemm ** 986c2aa98e2SPeter Wemm ** Returns: 987c2aa98e2SPeter Wemm ** a pointer to the new version. 988c2aa98e2SPeter Wemm ** 989c2aa98e2SPeter Wemm ** Side Effects: 990c2aa98e2SPeter Wemm ** none. 991c2aa98e2SPeter Wemm ** 992c2aa98e2SPeter Wemm ** Warning: 993c2aa98e2SPeter Wemm ** The return value is saved in local storage and should 994c2aa98e2SPeter Wemm ** be copied if it is to be reused. 995c2aa98e2SPeter Wemm */ 996c2aa98e2SPeter Wemm 997c2aa98e2SPeter Wemm char * 998c2aa98e2SPeter Wemm crackaddr(addr) 999c2aa98e2SPeter Wemm register char *addr; 1000c2aa98e2SPeter Wemm { 1001c2aa98e2SPeter Wemm register char *p; 1002c2aa98e2SPeter Wemm register char c; 1003c2aa98e2SPeter Wemm int cmtlev; 1004c2aa98e2SPeter Wemm int realcmtlev; 1005c2aa98e2SPeter Wemm int anglelev, realanglelev; 1006c2aa98e2SPeter Wemm int copylev; 1007c2aa98e2SPeter Wemm int bracklev; 1008c2aa98e2SPeter Wemm bool qmode; 1009c2aa98e2SPeter Wemm bool realqmode; 1010c2aa98e2SPeter Wemm bool skipping; 1011c2aa98e2SPeter Wemm bool putgmac = FALSE; 1012c2aa98e2SPeter Wemm bool quoteit = FALSE; 1013c2aa98e2SPeter Wemm bool gotangle = FALSE; 1014c2aa98e2SPeter Wemm bool gotcolon = FALSE; 1015c2aa98e2SPeter Wemm register char *bp; 1016c2aa98e2SPeter Wemm char *buflim; 1017c2aa98e2SPeter Wemm char *bufhead; 1018c2aa98e2SPeter Wemm char *addrhead; 1019c2aa98e2SPeter Wemm static char buf[MAXNAME + 1]; 1020c2aa98e2SPeter Wemm 1021c2aa98e2SPeter Wemm if (tTd(33, 1)) 10223299c2f1SGregory Neil Shapiro dprintf("crackaddr(%s)\n", addr); 1023c2aa98e2SPeter Wemm 1024c2aa98e2SPeter Wemm /* strip leading spaces */ 1025c2aa98e2SPeter Wemm while (*addr != '\0' && isascii(*addr) && isspace(*addr)) 1026c2aa98e2SPeter Wemm addr++; 1027c2aa98e2SPeter Wemm 1028c2aa98e2SPeter Wemm /* 1029c2aa98e2SPeter Wemm ** Start by assuming we have no angle brackets. This will be 1030c2aa98e2SPeter Wemm ** adjusted later if we find them. 1031c2aa98e2SPeter Wemm */ 1032c2aa98e2SPeter Wemm 1033c2aa98e2SPeter Wemm bp = bufhead = buf; 1034c2aa98e2SPeter Wemm buflim = &buf[sizeof buf - 7]; 1035c2aa98e2SPeter Wemm p = addrhead = addr; 1036c2aa98e2SPeter Wemm copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0; 1037c2aa98e2SPeter Wemm bracklev = 0; 1038c2aa98e2SPeter Wemm qmode = realqmode = FALSE; 1039c2aa98e2SPeter Wemm 1040c2aa98e2SPeter Wemm while ((c = *p++) != '\0') 1041c2aa98e2SPeter Wemm { 1042c2aa98e2SPeter Wemm /* 1043c2aa98e2SPeter Wemm ** If the buffer is overful, go into a special "skipping" 1044c2aa98e2SPeter Wemm ** mode that tries to keep legal syntax but doesn't actually 1045c2aa98e2SPeter Wemm ** output things. 1046c2aa98e2SPeter Wemm */ 1047c2aa98e2SPeter Wemm 1048c2aa98e2SPeter Wemm skipping = bp >= buflim; 1049c2aa98e2SPeter Wemm 1050c2aa98e2SPeter Wemm if (copylev > 0 && !skipping) 1051c2aa98e2SPeter Wemm *bp++ = c; 1052c2aa98e2SPeter Wemm 1053c2aa98e2SPeter Wemm /* check for backslash escapes */ 1054c2aa98e2SPeter Wemm if (c == '\\') 1055c2aa98e2SPeter Wemm { 1056c2aa98e2SPeter Wemm /* arrange to quote the address */ 1057c2aa98e2SPeter Wemm if (cmtlev <= 0 && !qmode) 1058c2aa98e2SPeter Wemm quoteit = TRUE; 1059c2aa98e2SPeter Wemm 1060c2aa98e2SPeter Wemm if ((c = *p++) == '\0') 1061c2aa98e2SPeter Wemm { 1062c2aa98e2SPeter Wemm /* too far */ 1063c2aa98e2SPeter Wemm p--; 1064c2aa98e2SPeter Wemm goto putg; 1065c2aa98e2SPeter Wemm } 1066c2aa98e2SPeter Wemm if (copylev > 0 && !skipping) 1067c2aa98e2SPeter Wemm *bp++ = c; 1068c2aa98e2SPeter Wemm goto putg; 1069c2aa98e2SPeter Wemm } 1070c2aa98e2SPeter Wemm 1071c2aa98e2SPeter Wemm /* check for quoted strings */ 1072c2aa98e2SPeter Wemm if (c == '"' && cmtlev <= 0) 1073c2aa98e2SPeter Wemm { 1074c2aa98e2SPeter Wemm qmode = !qmode; 1075c2aa98e2SPeter Wemm if (copylev > 0 && !skipping) 1076c2aa98e2SPeter Wemm realqmode = !realqmode; 1077c2aa98e2SPeter Wemm continue; 1078c2aa98e2SPeter Wemm } 1079c2aa98e2SPeter Wemm if (qmode) 1080c2aa98e2SPeter Wemm goto putg; 1081c2aa98e2SPeter Wemm 1082c2aa98e2SPeter Wemm /* check for comments */ 1083c2aa98e2SPeter Wemm if (c == '(') 1084c2aa98e2SPeter Wemm { 1085c2aa98e2SPeter Wemm cmtlev++; 1086c2aa98e2SPeter Wemm 1087c2aa98e2SPeter Wemm /* allow space for closing paren */ 1088c2aa98e2SPeter Wemm if (!skipping) 1089c2aa98e2SPeter Wemm { 1090c2aa98e2SPeter Wemm buflim--; 1091c2aa98e2SPeter Wemm realcmtlev++; 1092c2aa98e2SPeter Wemm if (copylev++ <= 0) 1093c2aa98e2SPeter Wemm { 1094c2aa98e2SPeter Wemm if (bp != bufhead) 1095c2aa98e2SPeter Wemm *bp++ = ' '; 1096c2aa98e2SPeter Wemm *bp++ = c; 1097c2aa98e2SPeter Wemm } 1098c2aa98e2SPeter Wemm } 1099c2aa98e2SPeter Wemm } 1100c2aa98e2SPeter Wemm if (cmtlev > 0) 1101c2aa98e2SPeter Wemm { 1102c2aa98e2SPeter Wemm if (c == ')') 1103c2aa98e2SPeter Wemm { 1104c2aa98e2SPeter Wemm cmtlev--; 1105c2aa98e2SPeter Wemm copylev--; 1106c2aa98e2SPeter Wemm if (!skipping) 1107c2aa98e2SPeter Wemm { 1108c2aa98e2SPeter Wemm realcmtlev--; 1109c2aa98e2SPeter Wemm buflim++; 1110c2aa98e2SPeter Wemm } 1111c2aa98e2SPeter Wemm } 1112c2aa98e2SPeter Wemm continue; 1113c2aa98e2SPeter Wemm } 1114c2aa98e2SPeter Wemm else if (c == ')') 1115c2aa98e2SPeter Wemm { 1116c2aa98e2SPeter Wemm /* syntax error: unmatched ) */ 1117c2aa98e2SPeter Wemm if (copylev > 0 && !skipping) 1118c2aa98e2SPeter Wemm bp--; 1119c2aa98e2SPeter Wemm } 1120c2aa98e2SPeter Wemm 1121c2aa98e2SPeter Wemm /* count nesting on [ ... ] (for IPv6 domain literals) */ 1122c2aa98e2SPeter Wemm if (c == '[') 1123c2aa98e2SPeter Wemm bracklev++; 1124c2aa98e2SPeter Wemm else if (c == ']') 1125c2aa98e2SPeter Wemm bracklev--; 1126c2aa98e2SPeter Wemm 1127c2aa98e2SPeter Wemm /* check for group: list; syntax */ 1128c2aa98e2SPeter Wemm if (c == ':' && anglelev <= 0 && bracklev <= 0 && 1129c2aa98e2SPeter Wemm !gotcolon && !ColonOkInAddr) 1130c2aa98e2SPeter Wemm { 1131c2aa98e2SPeter Wemm register char *q; 1132c2aa98e2SPeter Wemm 1133c2aa98e2SPeter Wemm /* 1134c2aa98e2SPeter Wemm ** Check for DECnet phase IV ``::'' (host::user) 1135c2aa98e2SPeter Wemm ** or ** DECnet phase V ``:.'' syntaxes. The latter 1136c2aa98e2SPeter Wemm ** covers ``user@DEC:.tay.myhost'' and 1137c2aa98e2SPeter Wemm ** ``DEC:.tay.myhost::user'' syntaxes (bletch). 1138c2aa98e2SPeter Wemm */ 1139c2aa98e2SPeter Wemm 1140c2aa98e2SPeter Wemm if (*p == ':' || *p == '.') 1141c2aa98e2SPeter Wemm { 1142c2aa98e2SPeter Wemm if (cmtlev <= 0 && !qmode) 1143c2aa98e2SPeter Wemm quoteit = TRUE; 1144c2aa98e2SPeter Wemm if (copylev > 0 && !skipping) 1145c2aa98e2SPeter Wemm { 1146c2aa98e2SPeter Wemm *bp++ = c; 1147c2aa98e2SPeter Wemm *bp++ = *p; 1148c2aa98e2SPeter Wemm } 1149c2aa98e2SPeter Wemm p++; 1150c2aa98e2SPeter Wemm goto putg; 1151c2aa98e2SPeter Wemm } 1152c2aa98e2SPeter Wemm 1153c2aa98e2SPeter Wemm gotcolon = TRUE; 1154c2aa98e2SPeter Wemm 1155c2aa98e2SPeter Wemm bp = bufhead; 1156c2aa98e2SPeter Wemm if (quoteit) 1157c2aa98e2SPeter Wemm { 1158c2aa98e2SPeter Wemm *bp++ = '"'; 1159c2aa98e2SPeter Wemm 1160c2aa98e2SPeter Wemm /* back up over the ':' and any spaces */ 1161c2aa98e2SPeter Wemm --p; 1162c2aa98e2SPeter Wemm while (isascii(*--p) && isspace(*p)) 1163c2aa98e2SPeter Wemm continue; 1164c2aa98e2SPeter Wemm p++; 1165c2aa98e2SPeter Wemm } 1166c2aa98e2SPeter Wemm for (q = addrhead; q < p; ) 1167c2aa98e2SPeter Wemm { 1168c2aa98e2SPeter Wemm c = *q++; 1169c2aa98e2SPeter Wemm if (bp < buflim) 1170c2aa98e2SPeter Wemm { 1171c2aa98e2SPeter Wemm if (quoteit && c == '"') 1172c2aa98e2SPeter Wemm *bp++ = '\\'; 1173c2aa98e2SPeter Wemm *bp++ = c; 1174c2aa98e2SPeter Wemm } 1175c2aa98e2SPeter Wemm } 1176c2aa98e2SPeter Wemm if (quoteit) 1177c2aa98e2SPeter Wemm { 1178c2aa98e2SPeter Wemm if (bp == &bufhead[1]) 1179c2aa98e2SPeter Wemm bp--; 1180c2aa98e2SPeter Wemm else 1181c2aa98e2SPeter Wemm *bp++ = '"'; 1182c2aa98e2SPeter Wemm while ((c = *p++) != ':') 1183c2aa98e2SPeter Wemm { 1184c2aa98e2SPeter Wemm if (bp < buflim) 1185c2aa98e2SPeter Wemm *bp++ = c; 1186c2aa98e2SPeter Wemm } 1187c2aa98e2SPeter Wemm *bp++ = c; 1188c2aa98e2SPeter Wemm } 1189c2aa98e2SPeter Wemm 1190c2aa98e2SPeter Wemm /* any trailing white space is part of group: */ 1191c2aa98e2SPeter Wemm while (isascii(*p) && isspace(*p) && bp < buflim) 1192c2aa98e2SPeter Wemm *bp++ = *p++; 1193c2aa98e2SPeter Wemm copylev = 0; 1194c2aa98e2SPeter Wemm putgmac = quoteit = FALSE; 1195c2aa98e2SPeter Wemm bufhead = bp; 1196c2aa98e2SPeter Wemm addrhead = p; 1197c2aa98e2SPeter Wemm continue; 1198c2aa98e2SPeter Wemm } 1199c2aa98e2SPeter Wemm 1200c2aa98e2SPeter Wemm if (c == ';' && copylev <= 0 && !ColonOkInAddr) 1201c2aa98e2SPeter Wemm { 1202c2aa98e2SPeter Wemm if (bp < buflim) 1203c2aa98e2SPeter Wemm *bp++ = c; 1204c2aa98e2SPeter Wemm } 1205c2aa98e2SPeter Wemm 1206c2aa98e2SPeter Wemm /* check for characters that may have to be quoted */ 1207c2aa98e2SPeter Wemm if (strchr(MustQuoteChars, c) != NULL) 1208c2aa98e2SPeter Wemm { 1209c2aa98e2SPeter Wemm /* 1210c2aa98e2SPeter Wemm ** If these occur as the phrase part of a <> 1211c2aa98e2SPeter Wemm ** construct, but are not inside of () or already 1212c2aa98e2SPeter Wemm ** quoted, they will have to be quoted. Note that 1213c2aa98e2SPeter Wemm ** now (but don't actually do the quoting). 1214c2aa98e2SPeter Wemm */ 1215c2aa98e2SPeter Wemm 1216c2aa98e2SPeter Wemm if (cmtlev <= 0 && !qmode) 1217c2aa98e2SPeter Wemm quoteit = TRUE; 1218c2aa98e2SPeter Wemm } 1219c2aa98e2SPeter Wemm 1220c2aa98e2SPeter Wemm /* check for angle brackets */ 1221c2aa98e2SPeter Wemm if (c == '<') 1222c2aa98e2SPeter Wemm { 1223c2aa98e2SPeter Wemm register char *q; 1224c2aa98e2SPeter Wemm 1225c2aa98e2SPeter Wemm /* assume first of two angles is bogus */ 1226c2aa98e2SPeter Wemm if (gotangle) 1227c2aa98e2SPeter Wemm quoteit = TRUE; 1228c2aa98e2SPeter Wemm gotangle = TRUE; 1229c2aa98e2SPeter Wemm 1230c2aa98e2SPeter Wemm /* oops -- have to change our mind */ 1231c2aa98e2SPeter Wemm anglelev = 1; 1232c2aa98e2SPeter Wemm if (!skipping) 1233c2aa98e2SPeter Wemm realanglelev = 1; 1234c2aa98e2SPeter Wemm 1235c2aa98e2SPeter Wemm bp = bufhead; 1236c2aa98e2SPeter Wemm if (quoteit) 1237c2aa98e2SPeter Wemm { 1238c2aa98e2SPeter Wemm *bp++ = '"'; 1239c2aa98e2SPeter Wemm 1240c2aa98e2SPeter Wemm /* back up over the '<' and any spaces */ 1241c2aa98e2SPeter Wemm --p; 1242c2aa98e2SPeter Wemm while (isascii(*--p) && isspace(*p)) 1243c2aa98e2SPeter Wemm continue; 1244c2aa98e2SPeter Wemm p++; 1245c2aa98e2SPeter Wemm } 1246c2aa98e2SPeter Wemm for (q = addrhead; q < p; ) 1247c2aa98e2SPeter Wemm { 1248c2aa98e2SPeter Wemm c = *q++; 1249c2aa98e2SPeter Wemm if (bp < buflim) 1250c2aa98e2SPeter Wemm { 1251c2aa98e2SPeter Wemm if (quoteit && c == '"') 1252c2aa98e2SPeter Wemm *bp++ = '\\'; 1253c2aa98e2SPeter Wemm *bp++ = c; 1254c2aa98e2SPeter Wemm } 1255c2aa98e2SPeter Wemm } 1256c2aa98e2SPeter Wemm if (quoteit) 1257c2aa98e2SPeter Wemm { 1258c2aa98e2SPeter Wemm if (bp == &buf[1]) 1259c2aa98e2SPeter Wemm bp--; 1260c2aa98e2SPeter Wemm else 1261c2aa98e2SPeter Wemm *bp++ = '"'; 1262c2aa98e2SPeter Wemm while ((c = *p++) != '<') 1263c2aa98e2SPeter Wemm { 1264c2aa98e2SPeter Wemm if (bp < buflim) 1265c2aa98e2SPeter Wemm *bp++ = c; 1266c2aa98e2SPeter Wemm } 1267c2aa98e2SPeter Wemm *bp++ = c; 1268c2aa98e2SPeter Wemm } 1269c2aa98e2SPeter Wemm copylev = 0; 1270c2aa98e2SPeter Wemm putgmac = quoteit = FALSE; 1271c2aa98e2SPeter Wemm continue; 1272c2aa98e2SPeter Wemm } 1273c2aa98e2SPeter Wemm 1274c2aa98e2SPeter Wemm if (c == '>') 1275c2aa98e2SPeter Wemm { 1276c2aa98e2SPeter Wemm if (anglelev > 0) 1277c2aa98e2SPeter Wemm { 1278c2aa98e2SPeter Wemm anglelev--; 1279c2aa98e2SPeter Wemm if (!skipping) 1280c2aa98e2SPeter Wemm { 1281c2aa98e2SPeter Wemm realanglelev--; 1282c2aa98e2SPeter Wemm buflim++; 1283c2aa98e2SPeter Wemm } 1284c2aa98e2SPeter Wemm } 1285c2aa98e2SPeter Wemm else if (!skipping) 1286c2aa98e2SPeter Wemm { 1287c2aa98e2SPeter Wemm /* syntax error: unmatched > */ 1288c2aa98e2SPeter Wemm if (copylev > 0) 1289c2aa98e2SPeter Wemm bp--; 1290c2aa98e2SPeter Wemm quoteit = TRUE; 1291c2aa98e2SPeter Wemm continue; 1292c2aa98e2SPeter Wemm } 1293c2aa98e2SPeter Wemm if (copylev++ <= 0) 1294c2aa98e2SPeter Wemm *bp++ = c; 1295c2aa98e2SPeter Wemm continue; 1296c2aa98e2SPeter Wemm } 1297c2aa98e2SPeter Wemm 1298c2aa98e2SPeter Wemm /* must be a real address character */ 1299c2aa98e2SPeter Wemm putg: 1300c2aa98e2SPeter Wemm if (copylev <= 0 && !putgmac) 1301c2aa98e2SPeter Wemm { 1302c2aa98e2SPeter Wemm if (bp > bufhead && bp[-1] == ')') 1303c2aa98e2SPeter Wemm *bp++ = ' '; 1304c2aa98e2SPeter Wemm *bp++ = MACROEXPAND; 1305c2aa98e2SPeter Wemm *bp++ = 'g'; 1306c2aa98e2SPeter Wemm putgmac = TRUE; 1307c2aa98e2SPeter Wemm } 1308c2aa98e2SPeter Wemm } 1309c2aa98e2SPeter Wemm 1310c2aa98e2SPeter Wemm /* repair any syntactic damage */ 1311c2aa98e2SPeter Wemm if (realqmode) 1312c2aa98e2SPeter Wemm *bp++ = '"'; 1313c2aa98e2SPeter Wemm while (realcmtlev-- > 0) 1314c2aa98e2SPeter Wemm *bp++ = ')'; 1315c2aa98e2SPeter Wemm while (realanglelev-- > 0) 1316c2aa98e2SPeter Wemm *bp++ = '>'; 1317c2aa98e2SPeter Wemm *bp++ = '\0'; 1318c2aa98e2SPeter Wemm 1319c2aa98e2SPeter Wemm if (tTd(33, 1)) 1320c2aa98e2SPeter Wemm { 13213299c2f1SGregory Neil Shapiro dprintf("crackaddr=>`"); 1322c2aa98e2SPeter Wemm xputs(buf); 13233299c2f1SGregory Neil Shapiro dprintf("'\n"); 1324c2aa98e2SPeter Wemm } 1325c2aa98e2SPeter Wemm 13263299c2f1SGregory Neil Shapiro return buf; 1327c2aa98e2SPeter Wemm } 1328c2aa98e2SPeter Wemm /* 1329c2aa98e2SPeter Wemm ** PUTHEADER -- put the header part of a message from the in-core copy 1330c2aa98e2SPeter Wemm ** 1331c2aa98e2SPeter Wemm ** Parameters: 1332c2aa98e2SPeter Wemm ** mci -- the connection information. 13333299c2f1SGregory Neil Shapiro ** hdr -- the header to put. 1334c2aa98e2SPeter Wemm ** e -- envelope to use. 1335e01d6f61SPeter Wemm ** flags -- MIME conversion flags. 1336c2aa98e2SPeter Wemm ** 1337c2aa98e2SPeter Wemm ** Returns: 1338c2aa98e2SPeter Wemm ** none. 1339c2aa98e2SPeter Wemm ** 1340c2aa98e2SPeter Wemm ** Side Effects: 1341c2aa98e2SPeter Wemm ** none. 1342c2aa98e2SPeter Wemm */ 1343c2aa98e2SPeter Wemm 1344c2aa98e2SPeter Wemm /* 1345c2aa98e2SPeter Wemm * Macro for fast max (not available in e.g. DG/UX, 386/ix). 1346c2aa98e2SPeter Wemm */ 1347c2aa98e2SPeter Wemm #ifndef MAX 1348c2aa98e2SPeter Wemm # define MAX(a,b) (((a)>(b))?(a):(b)) 13493299c2f1SGregory Neil Shapiro #endif /* ! MAX */ 1350c2aa98e2SPeter Wemm 1351c2aa98e2SPeter Wemm void 1352e01d6f61SPeter Wemm putheader(mci, hdr, e, flags) 1353c2aa98e2SPeter Wemm register MCI *mci; 1354c2aa98e2SPeter Wemm HDR *hdr; 1355c2aa98e2SPeter Wemm register ENVELOPE *e; 1356e01d6f61SPeter Wemm int flags; 1357c2aa98e2SPeter Wemm { 1358c2aa98e2SPeter Wemm register HDR *h; 1359c2aa98e2SPeter Wemm char buf[MAX(MAXLINE,BUFSIZ)]; 1360c2aa98e2SPeter Wemm char obuf[MAXLINE]; 1361c2aa98e2SPeter Wemm 1362c2aa98e2SPeter Wemm if (tTd(34, 1)) 13633299c2f1SGregory Neil Shapiro dprintf("--- putheader, mailer = %s ---\n", 1364c2aa98e2SPeter Wemm mci->mci_mailer->m_name); 1365c2aa98e2SPeter Wemm 1366c2aa98e2SPeter Wemm /* 1367c2aa98e2SPeter Wemm ** If we're in MIME mode, we're not really in the header of the 1368c2aa98e2SPeter Wemm ** message, just the header of one of the parts of the body of 1369c2aa98e2SPeter Wemm ** the message. Therefore MCIF_INHEADER should not be turned on. 1370c2aa98e2SPeter Wemm */ 1371c2aa98e2SPeter Wemm 1372c2aa98e2SPeter Wemm if (!bitset(MCIF_INMIME, mci->mci_flags)) 1373c2aa98e2SPeter Wemm mci->mci_flags |= MCIF_INHEADER; 1374c2aa98e2SPeter Wemm 1375c2aa98e2SPeter Wemm for (h = hdr; h != NULL; h = h->h_link) 1376c2aa98e2SPeter Wemm { 1377c2aa98e2SPeter Wemm register char *p = h->h_value; 1378c2aa98e2SPeter Wemm 1379c2aa98e2SPeter Wemm if (tTd(34, 11)) 1380c2aa98e2SPeter Wemm { 13813299c2f1SGregory Neil Shapiro dprintf(" %s: ", h->h_field); 1382c2aa98e2SPeter Wemm xputs(p); 1383c2aa98e2SPeter Wemm } 1384c2aa98e2SPeter Wemm 13853299c2f1SGregory Neil Shapiro /* Skip empty headers */ 13863299c2f1SGregory Neil Shapiro if (h->h_value == NULL) 13873299c2f1SGregory Neil Shapiro continue; 13883299c2f1SGregory Neil Shapiro 138976b7bf71SPeter Wemm /* heuristic shortening of MIME fields to avoid MUA overflows */ 139076b7bf71SPeter Wemm if (MaxMimeFieldLength > 0 && 139176b7bf71SPeter Wemm wordinclass(h->h_field, 139276b7bf71SPeter Wemm macid("{checkMIMEFieldHeaders}", NULL))) 139376b7bf71SPeter Wemm { 1394c46d91b7SGregory Neil Shapiro size_t len; 1395c46d91b7SGregory Neil Shapiro 1396c46d91b7SGregory Neil Shapiro len = fix_mime_header(h->h_value); 1397c46d91b7SGregory Neil Shapiro if (len > 0) 139876b7bf71SPeter Wemm { 139976b7bf71SPeter Wemm sm_syslog(LOG_ALERT, e->e_id, 1400c46d91b7SGregory Neil Shapiro "Truncated MIME %s header due to field size (length = %ld) (possible attack)", 1401c46d91b7SGregory Neil Shapiro h->h_field, (unsigned long) len); 140276b7bf71SPeter Wemm if (tTd(34, 11)) 1403c46d91b7SGregory Neil Shapiro dprintf(" truncated MIME %s header due to field size (length = %ld) (possible attack)\n", 1404c46d91b7SGregory Neil Shapiro h->h_field, 1405c46d91b7SGregory Neil Shapiro (unsigned long) len); 140676b7bf71SPeter Wemm } 140776b7bf71SPeter Wemm } 140876b7bf71SPeter Wemm 140976b7bf71SPeter Wemm if (MaxMimeHeaderLength > 0 && 141076b7bf71SPeter Wemm wordinclass(h->h_field, 141176b7bf71SPeter Wemm macid("{checkMIMETextHeaders}", NULL))) 141276b7bf71SPeter Wemm { 1413c46d91b7SGregory Neil Shapiro size_t len; 1414c46d91b7SGregory Neil Shapiro 1415c46d91b7SGregory Neil Shapiro len = strlen(h->h_value); 1416c46d91b7SGregory Neil Shapiro if (len > (size_t) MaxMimeHeaderLength) 141776b7bf71SPeter Wemm { 141876b7bf71SPeter Wemm h->h_value[MaxMimeHeaderLength - 1] = '\0'; 141976b7bf71SPeter Wemm sm_syslog(LOG_ALERT, e->e_id, 1420c46d91b7SGregory Neil Shapiro "Truncated long MIME %s header (length = %ld) (possible attack)", 1421c46d91b7SGregory Neil Shapiro h->h_field, (unsigned long) len); 142276b7bf71SPeter Wemm if (tTd(34, 11)) 1423c46d91b7SGregory Neil Shapiro dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 1424c46d91b7SGregory Neil Shapiro h->h_field, 1425c46d91b7SGregory Neil Shapiro (unsigned long) len); 142676b7bf71SPeter Wemm } 142776b7bf71SPeter Wemm } 142876b7bf71SPeter Wemm 142976b7bf71SPeter Wemm if (MaxMimeHeaderLength > 0 && 143076b7bf71SPeter Wemm wordinclass(h->h_field, 143176b7bf71SPeter Wemm macid("{checkMIMEHeaders}", NULL))) 143276b7bf71SPeter Wemm { 1433c46d91b7SGregory Neil Shapiro size_t len; 1434c46d91b7SGregory Neil Shapiro 1435c46d91b7SGregory Neil Shapiro len = strlen(h->h_value); 1436c46d91b7SGregory Neil Shapiro if (shorten_rfc822_string(h->h_value, 1437c46d91b7SGregory Neil Shapiro MaxMimeHeaderLength)) 143876b7bf71SPeter Wemm { 143976b7bf71SPeter Wemm sm_syslog(LOG_ALERT, e->e_id, 1440c46d91b7SGregory Neil Shapiro "Truncated long MIME %s header (length = %ld) (possible attack)", 1441c46d91b7SGregory Neil Shapiro h->h_field, (unsigned long) len); 144276b7bf71SPeter Wemm if (tTd(34, 11)) 1443c46d91b7SGregory Neil Shapiro dprintf(" truncated long MIME %s header (length = %ld) (possible attack)\n", 1444c46d91b7SGregory Neil Shapiro h->h_field, 1445c46d91b7SGregory Neil Shapiro (unsigned long) len); 144676b7bf71SPeter Wemm } 144776b7bf71SPeter Wemm } 144876b7bf71SPeter Wemm 1449e01d6f61SPeter Wemm /* 1450e01d6f61SPeter Wemm ** Suppress Content-Transfer-Encoding: if we are MIMEing 1451e01d6f61SPeter Wemm ** and we are potentially converting from 8 bit to 7 bit 1452e01d6f61SPeter Wemm ** MIME. If converting, add a new CTE header in 1453e01d6f61SPeter Wemm ** mime8to7(). 1454e01d6f61SPeter Wemm */ 1455c2aa98e2SPeter Wemm if (bitset(H_CTE, h->h_flags) && 1456e01d6f61SPeter Wemm bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, 1457e01d6f61SPeter Wemm mci->mci_flags) && 1458e01d6f61SPeter Wemm !bitset(M87F_NO8TO7, flags)) 1459c2aa98e2SPeter Wemm { 1460c2aa98e2SPeter Wemm if (tTd(34, 11)) 14613299c2f1SGregory Neil Shapiro dprintf(" (skipped (content-transfer-encoding))\n"); 1462c2aa98e2SPeter Wemm continue; 1463c2aa98e2SPeter Wemm } 1464c2aa98e2SPeter Wemm 1465c2aa98e2SPeter Wemm if (bitset(MCIF_INMIME, mci->mci_flags)) 1466c2aa98e2SPeter Wemm { 1467c2aa98e2SPeter Wemm if (tTd(34, 11)) 14683299c2f1SGregory Neil Shapiro dprintf("\n"); 1469c2aa98e2SPeter Wemm put_vanilla_header(h, p, mci); 1470c2aa98e2SPeter Wemm continue; 1471c2aa98e2SPeter Wemm } 1472c2aa98e2SPeter Wemm 1473c2aa98e2SPeter Wemm if (bitset(H_CHECK|H_ACHECK, h->h_flags) && 14743299c2f1SGregory Neil Shapiro !bitintersect(h->h_mflags, mci->mci_mailer->m_flags) && 14753299c2f1SGregory Neil Shapiro (h->h_macro == '\0' || 1476c46d91b7SGregory Neil Shapiro macvalue(bitidx(h->h_macro), e) == NULL)) 1477c2aa98e2SPeter Wemm { 1478c2aa98e2SPeter Wemm if (tTd(34, 11)) 14793299c2f1SGregory Neil Shapiro dprintf(" (skipped)\n"); 1480c2aa98e2SPeter Wemm continue; 1481c2aa98e2SPeter Wemm } 1482c2aa98e2SPeter Wemm 1483c2aa98e2SPeter Wemm /* handle Resent-... headers specially */ 1484c2aa98e2SPeter Wemm if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) 1485c2aa98e2SPeter Wemm { 1486c2aa98e2SPeter Wemm if (tTd(34, 11)) 14873299c2f1SGregory Neil Shapiro dprintf(" (skipped (resent))\n"); 1488c2aa98e2SPeter Wemm continue; 1489c2aa98e2SPeter Wemm } 1490c2aa98e2SPeter Wemm 1491c2aa98e2SPeter Wemm /* suppress return receipts if requested */ 1492c2aa98e2SPeter Wemm if (bitset(H_RECEIPTTO, h->h_flags) && 1493c2aa98e2SPeter Wemm (RrtImpliesDsn || bitset(EF_NORECEIPT, e->e_flags))) 1494c2aa98e2SPeter Wemm { 1495c2aa98e2SPeter Wemm if (tTd(34, 11)) 14963299c2f1SGregory Neil Shapiro dprintf(" (skipped (receipt))\n"); 1497c2aa98e2SPeter Wemm continue; 1498c2aa98e2SPeter Wemm } 1499c2aa98e2SPeter Wemm 1500c2aa98e2SPeter Wemm /* macro expand value if generated internally */ 15013299c2f1SGregory Neil Shapiro if (bitset(H_DEFAULT, h->h_flags) || 15023299c2f1SGregory Neil Shapiro bitset(H_BINDLATE, h->h_flags)) 1503c2aa98e2SPeter Wemm { 1504c2aa98e2SPeter Wemm expand(p, buf, sizeof buf, e); 1505c2aa98e2SPeter Wemm p = buf; 1506c2aa98e2SPeter Wemm if (*p == '\0') 1507c2aa98e2SPeter Wemm { 1508c2aa98e2SPeter Wemm if (tTd(34, 11)) 15093299c2f1SGregory Neil Shapiro dprintf(" (skipped -- null value)\n"); 1510c2aa98e2SPeter Wemm continue; 1511c2aa98e2SPeter Wemm } 1512c2aa98e2SPeter Wemm } 1513c2aa98e2SPeter Wemm 1514c2aa98e2SPeter Wemm if (bitset(H_BCC, h->h_flags)) 1515c2aa98e2SPeter Wemm { 1516c2aa98e2SPeter Wemm /* Bcc: field -- either truncate or delete */ 1517c2aa98e2SPeter Wemm if (bitset(EF_DELETE_BCC, e->e_flags)) 1518c2aa98e2SPeter Wemm { 1519c2aa98e2SPeter Wemm if (tTd(34, 11)) 15203299c2f1SGregory Neil Shapiro dprintf(" (skipped -- bcc)\n"); 1521c2aa98e2SPeter Wemm } 1522c2aa98e2SPeter Wemm else 1523c2aa98e2SPeter Wemm { 1524c2aa98e2SPeter Wemm /* no other recipient headers: truncate value */ 1525c2aa98e2SPeter Wemm (void) snprintf(obuf, sizeof obuf, "%s:", 1526c2aa98e2SPeter Wemm h->h_field); 1527c2aa98e2SPeter Wemm putline(obuf, mci); 1528c2aa98e2SPeter Wemm } 1529c2aa98e2SPeter Wemm continue; 1530c2aa98e2SPeter Wemm } 1531c2aa98e2SPeter Wemm 1532c2aa98e2SPeter Wemm if (tTd(34, 11)) 15333299c2f1SGregory Neil Shapiro dprintf("\n"); 1534c2aa98e2SPeter Wemm 1535c2aa98e2SPeter Wemm if (bitset(H_FROM|H_RCPT, h->h_flags)) 1536c2aa98e2SPeter Wemm { 1537c2aa98e2SPeter Wemm /* address field */ 1538c2aa98e2SPeter Wemm bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); 1539c2aa98e2SPeter Wemm 1540c2aa98e2SPeter Wemm if (bitset(H_FROM, h->h_flags)) 1541c2aa98e2SPeter Wemm oldstyle = FALSE; 1542c2aa98e2SPeter Wemm commaize(h, p, oldstyle, mci, e); 1543c2aa98e2SPeter Wemm } 1544c2aa98e2SPeter Wemm else 1545c2aa98e2SPeter Wemm { 1546c2aa98e2SPeter Wemm put_vanilla_header(h, p, mci); 1547c2aa98e2SPeter Wemm } 1548c2aa98e2SPeter Wemm } 1549c2aa98e2SPeter Wemm 1550c2aa98e2SPeter Wemm /* 1551c2aa98e2SPeter Wemm ** If we are converting this to a MIME message, add the 15523299c2f1SGregory Neil Shapiro ** MIME headers (but not in MIME mode!). 1553c2aa98e2SPeter Wemm */ 1554c2aa98e2SPeter Wemm 1555c2aa98e2SPeter Wemm #if MIME8TO7 1556c2aa98e2SPeter Wemm if (bitset(MM_MIME8BIT, MimeMode) && 1557c2aa98e2SPeter Wemm bitset(EF_HAS8BIT, e->e_flags) && 1558c2aa98e2SPeter Wemm !bitset(EF_DONT_MIME, e->e_flags) && 1559c2aa98e2SPeter Wemm !bitnset(M_8BITS, mci->mci_mailer->m_flags) && 15603299c2f1SGregory Neil Shapiro !bitset(MCIF_CVT8TO7|MCIF_CVT7TO8|MCIF_INMIME, mci->mci_flags) && 15613299c2f1SGregory Neil Shapiro hvalue("MIME-Version", e->e_header) == NULL) 1562c2aa98e2SPeter Wemm { 1563c2aa98e2SPeter Wemm putline("MIME-Version: 1.0", mci); 1564c2aa98e2SPeter Wemm if (hvalue("Content-Type", e->e_header) == NULL) 1565c2aa98e2SPeter Wemm { 1566c2aa98e2SPeter Wemm snprintf(obuf, sizeof obuf, 1567c2aa98e2SPeter Wemm "Content-Type: text/plain; charset=%s", 1568c2aa98e2SPeter Wemm defcharset(e)); 1569c2aa98e2SPeter Wemm putline(obuf, mci); 1570c2aa98e2SPeter Wemm } 1571c2aa98e2SPeter Wemm if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL) 1572c2aa98e2SPeter Wemm putline("Content-Transfer-Encoding: 8bit", mci); 1573c2aa98e2SPeter Wemm } 15743299c2f1SGregory Neil Shapiro #endif /* MIME8TO7 */ 1575c2aa98e2SPeter Wemm } 1576c2aa98e2SPeter Wemm /* 1577c2aa98e2SPeter Wemm ** PUT_VANILLA_HEADER -- output a fairly ordinary header 1578c2aa98e2SPeter Wemm ** 1579c2aa98e2SPeter Wemm ** Parameters: 1580c2aa98e2SPeter Wemm ** h -- the structure describing this header 1581c2aa98e2SPeter Wemm ** v -- the value of this header 1582c2aa98e2SPeter Wemm ** mci -- the connection info for output 1583c2aa98e2SPeter Wemm ** 1584c2aa98e2SPeter Wemm ** Returns: 1585c2aa98e2SPeter Wemm ** none. 1586c2aa98e2SPeter Wemm */ 1587c2aa98e2SPeter Wemm 15883299c2f1SGregory Neil Shapiro static void 1589c2aa98e2SPeter Wemm put_vanilla_header(h, v, mci) 1590c2aa98e2SPeter Wemm HDR *h; 1591c2aa98e2SPeter Wemm char *v; 1592c2aa98e2SPeter Wemm MCI *mci; 1593c2aa98e2SPeter Wemm { 1594c2aa98e2SPeter Wemm register char *nlp; 1595c2aa98e2SPeter Wemm register char *obp; 1596c2aa98e2SPeter Wemm int putflags; 1597c2aa98e2SPeter Wemm char obuf[MAXLINE]; 1598c2aa98e2SPeter Wemm 1599c2aa98e2SPeter Wemm putflags = PXLF_HEADER; 1600c2aa98e2SPeter Wemm if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 1601c2aa98e2SPeter Wemm putflags |= PXLF_STRIP8BIT; 1602c2aa98e2SPeter Wemm (void) snprintf(obuf, sizeof obuf, "%.200s: ", h->h_field); 1603c2aa98e2SPeter Wemm obp = obuf + strlen(obuf); 1604c2aa98e2SPeter Wemm while ((nlp = strchr(v, '\n')) != NULL) 1605c2aa98e2SPeter Wemm { 1606c2aa98e2SPeter Wemm int l; 1607c2aa98e2SPeter Wemm 1608c2aa98e2SPeter Wemm l = nlp - v; 16093299c2f1SGregory Neil Shapiro if (SPACELEFT(obuf, obp) - 1 < (size_t)l) 1610c2aa98e2SPeter Wemm l = SPACELEFT(obuf, obp) - 1; 1611c2aa98e2SPeter Wemm 1612c2aa98e2SPeter Wemm snprintf(obp, SPACELEFT(obuf, obp), "%.*s", l, v); 1613c2aa98e2SPeter Wemm putxline(obuf, strlen(obuf), mci, putflags); 1614c2aa98e2SPeter Wemm v += l + 1; 1615c2aa98e2SPeter Wemm obp = obuf; 1616c2aa98e2SPeter Wemm if (*v != ' ' && *v != '\t') 1617c2aa98e2SPeter Wemm *obp++ = ' '; 1618c2aa98e2SPeter Wemm } 1619c2aa98e2SPeter Wemm snprintf(obp, SPACELEFT(obuf, obp), "%.*s", 16203299c2f1SGregory Neil Shapiro (int) sizeof obuf - (obp - obuf) - 1, v); 1621c2aa98e2SPeter Wemm putxline(obuf, strlen(obuf), mci, putflags); 1622c2aa98e2SPeter Wemm } 1623c2aa98e2SPeter Wemm /* 1624c2aa98e2SPeter Wemm ** COMMAIZE -- output a header field, making a comma-translated list. 1625c2aa98e2SPeter Wemm ** 1626c2aa98e2SPeter Wemm ** Parameters: 1627c2aa98e2SPeter Wemm ** h -- the header field to output. 1628c2aa98e2SPeter Wemm ** p -- the value to put in it. 1629c2aa98e2SPeter Wemm ** oldstyle -- TRUE if this is an old style header. 1630c2aa98e2SPeter Wemm ** mci -- the connection information. 1631c2aa98e2SPeter Wemm ** e -- the envelope containing the message. 1632c2aa98e2SPeter Wemm ** 1633c2aa98e2SPeter Wemm ** Returns: 1634c2aa98e2SPeter Wemm ** none. 1635c2aa98e2SPeter Wemm ** 1636c2aa98e2SPeter Wemm ** Side Effects: 1637c2aa98e2SPeter Wemm ** outputs "p" to file "fp". 1638c2aa98e2SPeter Wemm */ 1639c2aa98e2SPeter Wemm 1640c2aa98e2SPeter Wemm void 1641c2aa98e2SPeter Wemm commaize(h, p, oldstyle, mci, e) 1642c2aa98e2SPeter Wemm register HDR *h; 1643c2aa98e2SPeter Wemm register char *p; 1644c2aa98e2SPeter Wemm bool oldstyle; 1645c2aa98e2SPeter Wemm register MCI *mci; 1646c2aa98e2SPeter Wemm register ENVELOPE *e; 1647c2aa98e2SPeter Wemm { 1648c2aa98e2SPeter Wemm register char *obp; 1649c2aa98e2SPeter Wemm int opos; 1650c2aa98e2SPeter Wemm int omax; 1651c2aa98e2SPeter Wemm bool firstone = TRUE; 1652c2aa98e2SPeter Wemm int putflags = PXLF_HEADER; 1653c2aa98e2SPeter Wemm char obuf[MAXLINE + 3]; 1654c2aa98e2SPeter Wemm 1655c2aa98e2SPeter Wemm /* 1656c2aa98e2SPeter Wemm ** Output the address list translated by the 1657c2aa98e2SPeter Wemm ** mailer and with commas. 1658c2aa98e2SPeter Wemm */ 1659c2aa98e2SPeter Wemm 1660c2aa98e2SPeter Wemm if (tTd(14, 2)) 16613299c2f1SGregory Neil Shapiro dprintf("commaize(%s: %s)\n", h->h_field, p); 1662c2aa98e2SPeter Wemm 1663c2aa98e2SPeter Wemm if (bitnset(M_7BITHDRS, mci->mci_mailer->m_flags)) 1664c2aa98e2SPeter Wemm putflags |= PXLF_STRIP8BIT; 1665c2aa98e2SPeter Wemm 1666c2aa98e2SPeter Wemm obp = obuf; 1667c2aa98e2SPeter Wemm (void) snprintf(obp, SPACELEFT(obuf, obp), "%.200s: ", h->h_field); 1668c2aa98e2SPeter Wemm opos = strlen(h->h_field) + 2; 1669c2aa98e2SPeter Wemm if (opos > 202) 1670c2aa98e2SPeter Wemm opos = 202; 1671c2aa98e2SPeter Wemm obp += opos; 1672c2aa98e2SPeter Wemm omax = mci->mci_mailer->m_linelimit - 2; 1673c2aa98e2SPeter Wemm if (omax < 0 || omax > 78) 1674c2aa98e2SPeter Wemm omax = 78; 1675c2aa98e2SPeter Wemm 1676c2aa98e2SPeter Wemm /* 1677c2aa98e2SPeter Wemm ** Run through the list of values. 1678c2aa98e2SPeter Wemm */ 1679c2aa98e2SPeter Wemm 1680c2aa98e2SPeter Wemm while (*p != '\0') 1681c2aa98e2SPeter Wemm { 1682c2aa98e2SPeter Wemm register char *name; 1683c2aa98e2SPeter Wemm register int c; 1684c2aa98e2SPeter Wemm char savechar; 1685c2aa98e2SPeter Wemm int flags; 16863299c2f1SGregory Neil Shapiro auto int status; 1687c2aa98e2SPeter Wemm 1688c2aa98e2SPeter Wemm /* 1689c2aa98e2SPeter Wemm ** Find the end of the name. New style names 1690c2aa98e2SPeter Wemm ** end with a comma, old style names end with 1691c2aa98e2SPeter Wemm ** a space character. However, spaces do not 1692c2aa98e2SPeter Wemm ** necessarily delimit an old-style name -- at 1693c2aa98e2SPeter Wemm ** signs mean keep going. 1694c2aa98e2SPeter Wemm */ 1695c2aa98e2SPeter Wemm 1696c2aa98e2SPeter Wemm /* find end of name */ 1697c2aa98e2SPeter Wemm while ((isascii(*p) && isspace(*p)) || *p == ',') 1698c2aa98e2SPeter Wemm p++; 1699c2aa98e2SPeter Wemm name = p; 1700c2aa98e2SPeter Wemm for (;;) 1701c2aa98e2SPeter Wemm { 1702c2aa98e2SPeter Wemm auto char *oldp; 1703c2aa98e2SPeter Wemm char pvpbuf[PSBUFSIZE]; 1704c2aa98e2SPeter Wemm 1705c2aa98e2SPeter Wemm (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf, 1706c2aa98e2SPeter Wemm sizeof pvpbuf, &oldp, NULL); 1707c2aa98e2SPeter Wemm p = oldp; 1708c2aa98e2SPeter Wemm 1709c2aa98e2SPeter Wemm /* look to see if we have an at sign */ 1710c2aa98e2SPeter Wemm while (*p != '\0' && isascii(*p) && isspace(*p)) 1711c2aa98e2SPeter Wemm p++; 1712c2aa98e2SPeter Wemm 1713c2aa98e2SPeter Wemm if (*p != '@') 1714c2aa98e2SPeter Wemm { 1715c2aa98e2SPeter Wemm p = oldp; 1716c2aa98e2SPeter Wemm break; 1717c2aa98e2SPeter Wemm } 1718c2aa98e2SPeter Wemm p += *p == '@' ? 1 : 2; 1719c2aa98e2SPeter Wemm while (*p != '\0' && isascii(*p) && isspace(*p)) 1720c2aa98e2SPeter Wemm p++; 1721c2aa98e2SPeter Wemm } 1722c2aa98e2SPeter Wemm /* at the end of one complete name */ 1723c2aa98e2SPeter Wemm 1724c2aa98e2SPeter Wemm /* strip off trailing white space */ 1725c2aa98e2SPeter Wemm while (p >= name && 1726c2aa98e2SPeter Wemm ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) 1727c2aa98e2SPeter Wemm p--; 1728c2aa98e2SPeter Wemm if (++p == name) 1729c2aa98e2SPeter Wemm continue; 1730c2aa98e2SPeter Wemm savechar = *p; 1731c2aa98e2SPeter Wemm *p = '\0'; 1732c2aa98e2SPeter Wemm 1733c2aa98e2SPeter Wemm /* translate the name to be relative */ 1734c2aa98e2SPeter Wemm flags = RF_HEADERADDR|RF_ADDDOMAIN; 1735c2aa98e2SPeter Wemm if (bitset(H_FROM, h->h_flags)) 1736c2aa98e2SPeter Wemm flags |= RF_SENDERADDR; 1737c2aa98e2SPeter Wemm #if USERDB 1738c2aa98e2SPeter Wemm else if (e->e_from.q_mailer != NULL && 1739c2aa98e2SPeter Wemm bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags)) 1740c2aa98e2SPeter Wemm { 1741c2aa98e2SPeter Wemm char *q; 1742c2aa98e2SPeter Wemm 1743c2aa98e2SPeter Wemm q = udbsender(name); 1744c2aa98e2SPeter Wemm if (q != NULL) 1745c2aa98e2SPeter Wemm name = q; 1746c2aa98e2SPeter Wemm } 17473299c2f1SGregory Neil Shapiro #endif /* USERDB */ 17483299c2f1SGregory Neil Shapiro status = EX_OK; 17493299c2f1SGregory Neil Shapiro name = remotename(name, mci->mci_mailer, flags, &status, e); 1750c2aa98e2SPeter Wemm if (*name == '\0') 1751c2aa98e2SPeter Wemm { 1752c2aa98e2SPeter Wemm *p = savechar; 1753c2aa98e2SPeter Wemm continue; 1754c2aa98e2SPeter Wemm } 1755c2aa98e2SPeter Wemm name = denlstring(name, FALSE, TRUE); 1756c2aa98e2SPeter Wemm 17573299c2f1SGregory Neil Shapiro /* 17583299c2f1SGregory Neil Shapiro ** record data progress so DNS timeouts 17593299c2f1SGregory Neil Shapiro ** don't cause DATA timeouts 17603299c2f1SGregory Neil Shapiro */ 17613299c2f1SGregory Neil Shapiro 17623299c2f1SGregory Neil Shapiro DataProgress = TRUE; 17633299c2f1SGregory Neil Shapiro 1764c2aa98e2SPeter Wemm /* output the name with nice formatting */ 1765c2aa98e2SPeter Wemm opos += strlen(name); 1766c2aa98e2SPeter Wemm if (!firstone) 1767c2aa98e2SPeter Wemm opos += 2; 1768c2aa98e2SPeter Wemm if (opos > omax && !firstone) 1769c2aa98e2SPeter Wemm { 1770c2aa98e2SPeter Wemm snprintf(obp, SPACELEFT(obuf, obp), ",\n"); 1771c2aa98e2SPeter Wemm putxline(obuf, strlen(obuf), mci, putflags); 1772c2aa98e2SPeter Wemm obp = obuf; 17733299c2f1SGregory Neil Shapiro (void) strlcpy(obp, " ", sizeof obp); 1774c2aa98e2SPeter Wemm opos = strlen(obp); 1775c2aa98e2SPeter Wemm obp += opos; 1776c2aa98e2SPeter Wemm opos += strlen(name); 1777c2aa98e2SPeter Wemm } 1778c2aa98e2SPeter Wemm else if (!firstone) 1779c2aa98e2SPeter Wemm { 1780c2aa98e2SPeter Wemm snprintf(obp, SPACELEFT(obuf, obp), ", "); 1781c2aa98e2SPeter Wemm obp += 2; 1782c2aa98e2SPeter Wemm } 1783c2aa98e2SPeter Wemm 1784c2aa98e2SPeter Wemm while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) 1785c2aa98e2SPeter Wemm *obp++ = c; 1786c2aa98e2SPeter Wemm firstone = FALSE; 1787c2aa98e2SPeter Wemm *p = savechar; 1788c2aa98e2SPeter Wemm } 1789c2aa98e2SPeter Wemm *obp = '\0'; 1790c2aa98e2SPeter Wemm putxline(obuf, strlen(obuf), mci, putflags); 1791c2aa98e2SPeter Wemm } 1792c2aa98e2SPeter Wemm /* 1793c2aa98e2SPeter Wemm ** COPYHEADER -- copy header list 1794c2aa98e2SPeter Wemm ** 1795c2aa98e2SPeter Wemm ** This routine is the equivalent of newstr for header lists 1796c2aa98e2SPeter Wemm ** 1797c2aa98e2SPeter Wemm ** Parameters: 1798c2aa98e2SPeter Wemm ** header -- list of header structures to copy. 1799c2aa98e2SPeter Wemm ** 1800c2aa98e2SPeter Wemm ** Returns: 1801c2aa98e2SPeter Wemm ** a copy of 'header'. 1802c2aa98e2SPeter Wemm ** 1803c2aa98e2SPeter Wemm ** Side Effects: 1804c2aa98e2SPeter Wemm ** none. 1805c2aa98e2SPeter Wemm */ 1806c2aa98e2SPeter Wemm 1807c2aa98e2SPeter Wemm HDR * 1808c2aa98e2SPeter Wemm copyheader(header) 1809c2aa98e2SPeter Wemm register HDR *header; 1810c2aa98e2SPeter Wemm { 1811c2aa98e2SPeter Wemm register HDR *newhdr; 1812c2aa98e2SPeter Wemm HDR *ret; 1813c2aa98e2SPeter Wemm register HDR **tail = &ret; 1814c2aa98e2SPeter Wemm 1815c2aa98e2SPeter Wemm while (header != NULL) 1816c2aa98e2SPeter Wemm { 18173299c2f1SGregory Neil Shapiro newhdr = (HDR *) xalloc(sizeof *newhdr); 1818c2aa98e2SPeter Wemm STRUCTCOPY(*header, *newhdr); 1819c2aa98e2SPeter Wemm *tail = newhdr; 1820c2aa98e2SPeter Wemm tail = &newhdr->h_link; 1821c2aa98e2SPeter Wemm header = header->h_link; 1822c2aa98e2SPeter Wemm } 1823c2aa98e2SPeter Wemm *tail = NULL; 1824c2aa98e2SPeter Wemm 1825c2aa98e2SPeter Wemm return ret; 1826c2aa98e2SPeter Wemm } 182776b7bf71SPeter Wemm /* 182876b7bf71SPeter Wemm ** FIX_MIME_HEADER -- possibly truncate/rebalance parameters in a MIME header 182976b7bf71SPeter Wemm ** 183076b7bf71SPeter Wemm ** Run through all of the parameters of a MIME header and 183176b7bf71SPeter Wemm ** possibly truncate and rebalance the parameter according 183276b7bf71SPeter Wemm ** to MaxMimeFieldLength. 183376b7bf71SPeter Wemm ** 183476b7bf71SPeter Wemm ** Parameters: 183576b7bf71SPeter Wemm ** string -- the full header 183676b7bf71SPeter Wemm ** 183776b7bf71SPeter Wemm ** Returns: 1838c46d91b7SGregory Neil Shapiro ** length of last offending field, 0 if all ok. 183976b7bf71SPeter Wemm ** 184076b7bf71SPeter Wemm ** Side Effects: 184176b7bf71SPeter Wemm ** string modified in place 184276b7bf71SPeter Wemm */ 184376b7bf71SPeter Wemm 1844c46d91b7SGregory Neil Shapiro static size_t 184576b7bf71SPeter Wemm fix_mime_header(string) 184676b7bf71SPeter Wemm char *string; 184776b7bf71SPeter Wemm { 184876b7bf71SPeter Wemm char *begin = string; 184976b7bf71SPeter Wemm char *end; 1850c46d91b7SGregory Neil Shapiro size_t len = 0; 1851c46d91b7SGregory Neil Shapiro size_t retlen = 0; 185276b7bf71SPeter Wemm 185376b7bf71SPeter Wemm if (string == NULL || *string == '\0') 1854c46d91b7SGregory Neil Shapiro return 0; 185576b7bf71SPeter Wemm 185676b7bf71SPeter Wemm /* Split on each ';' */ 185776b7bf71SPeter Wemm while ((end = find_character(begin, ';')) != NULL) 185876b7bf71SPeter Wemm { 185976b7bf71SPeter Wemm char save = *end; 186076b7bf71SPeter Wemm char *bp; 186176b7bf71SPeter Wemm 186276b7bf71SPeter Wemm *end = '\0'; 186376b7bf71SPeter Wemm 1864c46d91b7SGregory Neil Shapiro len = strlen(begin); 1865c46d91b7SGregory Neil Shapiro 186676b7bf71SPeter Wemm /* Shorten individual parameter */ 186776b7bf71SPeter Wemm if (shorten_rfc822_string(begin, MaxMimeFieldLength)) 1868c46d91b7SGregory Neil Shapiro retlen = len; 186976b7bf71SPeter Wemm 187076b7bf71SPeter Wemm /* Collapse the possibly shortened string with rest */ 187176b7bf71SPeter Wemm bp = begin + strlen(begin); 187276b7bf71SPeter Wemm if (bp != end) 187376b7bf71SPeter Wemm { 187476b7bf71SPeter Wemm char *ep = end; 187576b7bf71SPeter Wemm 187676b7bf71SPeter Wemm *end = save; 187776b7bf71SPeter Wemm end = bp; 187876b7bf71SPeter Wemm 187976b7bf71SPeter Wemm /* copy character by character due to overlap */ 188076b7bf71SPeter Wemm while (*ep != '\0') 188176b7bf71SPeter Wemm *bp++ = *ep++; 188276b7bf71SPeter Wemm *bp = '\0'; 188376b7bf71SPeter Wemm } 188476b7bf71SPeter Wemm else 188576b7bf71SPeter Wemm *end = save; 188676b7bf71SPeter Wemm if (*end == '\0') 188776b7bf71SPeter Wemm break; 188876b7bf71SPeter Wemm 188976b7bf71SPeter Wemm /* Move past ';' */ 189076b7bf71SPeter Wemm begin = end + 1; 189176b7bf71SPeter Wemm } 1892c46d91b7SGregory Neil Shapiro return retlen; 189376b7bf71SPeter Wemm } 1894