14091Seric # include <errno.h> 24091Seric # include "sendmail.h" 34091Seric 4*7365Seric SCCSID(@(#)headers.c 3.20 07/05/82); 54091Seric 64091Seric /* 74091Seric ** CHOMPHEADER -- process and save a header line. 84091Seric ** 94091Seric ** Called by collect and by readcf to deal with header lines. 104091Seric ** 114091Seric ** Parameters: 124091Seric ** line -- header as a text line. 134091Seric ** def -- if set, this is a default value. 144091Seric ** 154091Seric ** Returns: 164091Seric ** flags for this header. 174091Seric ** 184091Seric ** Side Effects: 194091Seric ** The header is saved on the header list. 204319Seric ** Contents of 'line' are destroyed. 214091Seric */ 224091Seric 234091Seric chompheader(line, def) 244091Seric char *line; 254091Seric bool def; 264091Seric { 274091Seric register char *p; 284091Seric register HDR *h; 294091Seric HDR **hp; 304091Seric extern bool isheader(); 314091Seric char *fname; 324091Seric char *fvalue; 334091Seric struct hdrinfo *hi; 344627Seric u_long mopts; 354627Seric extern u_long mfencode(); 364091Seric 374091Seric /* strip off trailing newline */ 384091Seric p = rindex(line, '\n'); 394091Seric if (p != NULL) 404091Seric *p = '\0'; 414091Seric 424627Seric /* strip off options */ 434627Seric mopts = 0; 444627Seric p = line; 454627Seric if (*p == '?') 464627Seric { 474627Seric /* have some */ 484627Seric register char *q = index(p + 1, *p); 494627Seric 504627Seric if (q != NULL) 514627Seric { 524627Seric *q++ = '\0'; 534627Seric mopts = mfencode(p + 1); 544627Seric p = q; 554627Seric } 564627Seric else 574627Seric syserr("chompheader: syntax error, line \"%s\"", line); 584627Seric } 594627Seric 604091Seric /* find canonical name */ 614627Seric fname = p; 624627Seric p = index(p, ':'); 634091Seric fvalue = &p[1]; 644091Seric while (isspace(*--p)) 654091Seric continue; 664091Seric *++p = '\0'; 674091Seric makelower(fname); 684091Seric 694091Seric /* strip field value on front */ 704091Seric if (*fvalue == ' ') 714091Seric fvalue++; 724091Seric 734372Seric /* hack, hack -- save From: line specially */ 746051Seric if (!def && !QueueRun && strcmp(fname, "from") == 0) 754372Seric { 766908Seric CurEnv->e_origfrom = newstr(fvalue); 774372Seric return (0); 784372Seric } 794372Seric 804091Seric /* search header list for this header */ 816908Seric for (hp = &CurEnv->e_header, h = CurEnv->e_header; h != NULL; hp = &h->h_link, h = h->h_link) 824091Seric { 835187Seric if (strcmp(fname, h->h_field) == 0 && bitset(H_DEFAULT, h->h_flags)) 844091Seric break; 854091Seric } 864091Seric 874091Seric /* see if it is a known type */ 884091Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 894091Seric { 904091Seric if (strcmp(hi->hi_field, fname) == 0) 914091Seric break; 924091Seric } 934091Seric 944091Seric /* if this means "end of header" quit now */ 954091Seric if (bitset(H_EOH, hi->hi_flags)) 964091Seric return (hi->hi_flags); 974091Seric 985187Seric /* don't put timestamps in every queue run */ 995187Seric if (QueueRun && h != NULL && bitset(H_FORCE, h->h_flags)) 1005187Seric return (h->h_flags); 1015187Seric 102*7365Seric /* count Mail-From: lines to avoid loops (simulate hop counts) */ 103*7365Seric if (strcmp(fname, "mail-from") == 0) 104*7365Seric HopCount++; 105*7365Seric 1064091Seric /* create/fill in a new node */ 1075187Seric if (h == NULL || bitset(H_FORCE, h->h_flags)) 1084091Seric { 1094091Seric /* create a new node */ 1105187Seric h = (HDR *) xalloc(sizeof *h); 1114091Seric h->h_field = newstr(fname); 1124091Seric h->h_value = NULL; 1135187Seric h->h_link = *hp; 1144091Seric h->h_flags = hi->hi_flags; 1154627Seric h->h_mflags = mopts | hi->hi_mflags; 1165187Seric *hp = h; 1174091Seric } 1184091Seric if (def) 1194091Seric h->h_flags |= H_DEFAULT; 1204627Seric else if (mopts == 0) 1214091Seric h->h_flags &= ~H_CHECK; 1224091Seric if (h->h_value != NULL) 1234091Seric free(h->h_value); 1244091Seric h->h_value = newstr(fvalue); 1255919Seric if (!def && GrabTo && bitset(H_RCPT, h->h_flags)) 1266908Seric sendto(h->h_value, 0, (ADDRESS *) NULL, &CurEnv->e_sendqueue); 1274091Seric 1285937Seric /* hack to see if this is a new format message */ 1295937Seric if (bitset(H_RCPT, h->h_flags) && 1305937Seric (index(fvalue, ',') != NULL || index(fvalue, '(') != NULL || 1315937Seric index(fvalue, '<') != NULL)) 1326908Seric CurEnv->e_oldstyle = FALSE; 1335937Seric 1344091Seric return (h->h_flags); 1354091Seric } 1364091Seric /* 1376980Seric ** ADDHEADER -- add a header entry to the end of the queue. 1386980Seric ** 1396980Seric ** This bypasses the special checking of chompheader. 1406980Seric ** 1416980Seric ** Parameters: 1426980Seric ** field -- the name of the header field. 1436980Seric ** value -- the value of the field. It must be lower-cased. 1446980Seric ** e -- the envelope to add them to. 1456980Seric ** 1466980Seric ** Returns: 1476980Seric ** none. 1486980Seric ** 1496980Seric ** Side Effects: 1506980Seric ** adds the field on the list of headers for this envelope. 1516980Seric */ 1526980Seric 1536980Seric addheader(field, value, e) 1546980Seric char *field; 1556980Seric char *value; 1566980Seric ENVELOPE *e; 1576980Seric { 1586980Seric register HDR *h; 1596980Seric register struct hdrinfo *hi; 1606980Seric HDR **hp; 1616980Seric 1626980Seric /* find info struct */ 1636980Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 1646980Seric { 1656980Seric if (strcmp(field, hi->hi_field) == 0) 1666980Seric break; 1676980Seric } 1686980Seric 1696980Seric /* find current place in list -- keep back pointer? */ 1706980Seric for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link) 1716980Seric { 1726980Seric if (strcmp(field, h->h_field) == 0) 1736980Seric break; 1746980Seric } 1756980Seric 1766980Seric /* allocate space for new header */ 1776980Seric h = (HDR *) xalloc(sizeof *h); 1786980Seric h->h_field = field; 1796980Seric h->h_value = newstr(value); 1806980Seric h->h_link = NULL; 1816980Seric h->h_flags = hi->hi_flags | H_DEFAULT; 1826980Seric h->h_mflags = hi->hi_mflags; 1836980Seric *hp = h; 1846980Seric } 1856980Seric /* 1864091Seric ** HVALUE -- return value of a header. 1874091Seric ** 1884091Seric ** Only "real" fields (i.e., ones that have not been supplied 1894091Seric ** as a default) are used. 1904091Seric ** 1914091Seric ** Parameters: 1924091Seric ** field -- the field name. 1934091Seric ** 1944091Seric ** Returns: 1954091Seric ** pointer to the value part. 1964091Seric ** NULL if not found. 1974091Seric ** 1984091Seric ** Side Effects: 1994091Seric ** sets the H_USED bit in the header if found. 2004091Seric */ 2014091Seric 2024091Seric char * 2034091Seric hvalue(field) 2044091Seric char *field; 2054091Seric { 2064091Seric register HDR *h; 2074091Seric 2086908Seric for (h = CurEnv->e_header; h != NULL; h = h->h_link) 2094091Seric { 2104091Seric if (!bitset(H_DEFAULT, h->h_flags) && strcmp(h->h_field, field) == 0) 2114091Seric { 2124091Seric h->h_flags |= H_USED; 2134091Seric return (h->h_value); 2144091Seric } 2154091Seric } 2164091Seric return (NULL); 2174091Seric } 2184091Seric /* 2194091Seric ** ISHEADER -- predicate telling if argument is a header. 2204091Seric ** 2214319Seric ** A line is a header if it has a single word followed by 2224319Seric ** optional white space followed by a colon. 2234319Seric ** 2244091Seric ** Parameters: 2254091Seric ** s -- string to check for possible headerness. 2264091Seric ** 2274091Seric ** Returns: 2284091Seric ** TRUE if s is a header. 2294091Seric ** FALSE otherwise. 2304091Seric ** 2314091Seric ** Side Effects: 2324091Seric ** none. 2334319Seric ** 2344319Seric ** Bugs: 2354319Seric ** According to RFC733, there should be a newline 2364319Seric ** permitted after the word but before the colon. 2374319Seric ** We don't seem to support that..... 2384091Seric */ 2394091Seric 2404091Seric bool 2414091Seric isheader(s) 2424091Seric register char *s; 2434091Seric { 2444091Seric if (!isalnum(*s)) 2454091Seric return (FALSE); 2464091Seric while (!isspace(*s) && *s != ':') 2474091Seric s++; 2484091Seric while (isspace(*s)) 2494091Seric s++; 2504091Seric return (*s == ':'); 2514091Seric } 2525919Seric /* 2535919Seric ** GETXPART -- extract the "signature" part of an address line. 2545919Seric ** 2555919Seric ** Try to extract the full name from a general address 2565919Seric ** field. We take anything which is a comment as a 2575919Seric ** first choice. Failing in that, we see if there is 2585919Seric ** a "machine readable" name (in <angle brackets>); if 2595919Seric ** so we take anything preceeding that clause. 2605919Seric ** 2615919Seric ** If we blow it here it's not all that serious. 2625919Seric ** 2635919Seric ** Parameters: 2645919Seric ** p -- line to crack. 2655919Seric ** 2665919Seric ** Returns: 2675919Seric ** signature part. 2685919Seric ** NULL if no signature part. 2695919Seric ** 2705919Seric ** Side Effects: 2715919Seric ** none. 2725919Seric */ 2735919Seric 2745919Seric char * 2755919Seric getxpart(p) 2765919Seric register char *p; 2775919Seric { 2785919Seric register char *q; 2795919Seric register char *rval = NULL; 2805919Seric 2815919Seric q = index(p, '('); 2825919Seric if (q != NULL) 2835919Seric { 2845919Seric int parenlev = 0; 2855919Seric 2865919Seric for (p = q; *p != '\0'; p++) 2875919Seric { 2885919Seric if (*p == '(') 2895919Seric parenlev++; 2905919Seric else if (*p == ')' && --parenlev <= 0) 2915919Seric break; 2925919Seric } 2935919Seric if (*p == ')') 2945919Seric { 2955919Seric *p = '\0'; 2965919Seric if (*++q != '\0') 2975919Seric rval = newstr(q); 2985919Seric *p = ')'; 2995919Seric } 3005919Seric } 3015919Seric else if ((q = index(p, '<')) != NULL) 3025919Seric { 3035919Seric char savec; 3045919Seric 3055919Seric while (*--q == ' ') 3065919Seric continue; 3075919Seric while (isspace(*p)) 3085919Seric p++; 3095919Seric savec = *++q; 3105919Seric *q = '\0'; 3115919Seric if (*p != '\0') 3125919Seric rval = newstr(p); 3135919Seric *q = savec; 3145919Seric } 3155919Seric 3165919Seric return (rval); 3175919Seric } 318