14091Seric # include <errno.h> 24091Seric # include "sendmail.h" 34091Seric 4*8095Seric SCCSID(@(#)headers.c 3.34 09/06/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 char *fname; 314091Seric char *fvalue; 324091Seric struct hdrinfo *hi; 334627Seric u_long mopts; 344627Seric extern u_long mfencode(); 357890Seric extern char *crackaddr(); 364091Seric 377677Seric # ifdef DEBUG 387677Seric if (tTd(31, 6)) 397677Seric printf("chompheader: %s\n", line); 407677Seric # endif DEBUG 417677Seric 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 734091Seric /* search header list for this header */ 746908Seric for (hp = &CurEnv->e_header, h = CurEnv->e_header; h != NULL; hp = &h->h_link, h = h->h_link) 754091Seric { 765187Seric if (strcmp(fname, h->h_field) == 0 && bitset(H_DEFAULT, h->h_flags)) 774091Seric break; 784091Seric } 794091Seric 804091Seric /* see if it is a known type */ 814091Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 824091Seric { 834091Seric if (strcmp(hi->hi_field, fname) == 0) 844091Seric break; 854091Seric } 864091Seric 874091Seric /* if this means "end of header" quit now */ 884091Seric if (bitset(H_EOH, hi->hi_flags)) 894091Seric return (hi->hi_flags); 904091Seric 917789Seric /* count Received: lines to avoid loops (simulate hop counts) */ 928066Seric if (bitset(H_TRACE, hi->hi_flags)) 937365Seric HopCount++; 947365Seric 954091Seric /* create/fill in a new node */ 965187Seric if (h == NULL || bitset(H_FORCE, h->h_flags)) 974091Seric { 984091Seric /* create a new node */ 995187Seric h = (HDR *) xalloc(sizeof *h); 1004091Seric h->h_field = newstr(fname); 1014091Seric h->h_value = NULL; 1025187Seric h->h_link = *hp; 1034627Seric h->h_mflags = mopts | hi->hi_mflags; 1045187Seric *hp = h; 1054091Seric } 1068066Seric h->h_flags = hi->hi_flags; 1074091Seric if (def) 1084091Seric h->h_flags |= H_DEFAULT; 1094627Seric else if (mopts == 0) 1104091Seric h->h_flags &= ~H_CHECK; 1114091Seric if (h->h_value != NULL) 1124091Seric free(h->h_value); 1138066Seric h->h_value = newstr(fvalue); 1144091Seric 1155937Seric /* hack to see if this is a new format message */ 116*8095Seric if (!def && bitset(H_RCPT|H_FROM, h->h_flags) && 1175937Seric (index(fvalue, ',') != NULL || index(fvalue, '(') != NULL || 1188089Seric index(fvalue, '<') != NULL || index(fvalue, ';') != NULL)) 1198089Seric { 1206908Seric CurEnv->e_oldstyle = FALSE; 1218089Seric } 1225937Seric 1238066Seric /* send to this person if we so desire */ 1248066Seric if (!def && GrabTo && bitset(H_RCPT, h->h_flags)) 1258082Seric sendto(h->h_value, (ADDRESS *) NULL, &CurEnv->e_sendqueue); 1268066Seric 1274091Seric return (h->h_flags); 1284091Seric } 1294091Seric /* 1306980Seric ** ADDHEADER -- add a header entry to the end of the queue. 1316980Seric ** 1326980Seric ** This bypasses the special checking of chompheader. 1336980Seric ** 1346980Seric ** Parameters: 1356980Seric ** field -- the name of the header field. 1366980Seric ** value -- the value of the field. It must be lower-cased. 1376980Seric ** e -- the envelope to add them to. 1386980Seric ** 1396980Seric ** Returns: 1406980Seric ** none. 1416980Seric ** 1426980Seric ** Side Effects: 1436980Seric ** adds the field on the list of headers for this envelope. 1446980Seric */ 1456980Seric 1466980Seric addheader(field, value, e) 1476980Seric char *field; 1486980Seric char *value; 1496980Seric ENVELOPE *e; 1506980Seric { 1516980Seric register HDR *h; 1526980Seric register struct hdrinfo *hi; 1536980Seric HDR **hp; 1546980Seric 1556980Seric /* find info struct */ 1566980Seric for (hi = HdrInfo; hi->hi_field != NULL; hi++) 1576980Seric { 1586980Seric if (strcmp(field, hi->hi_field) == 0) 1596980Seric break; 1606980Seric } 1616980Seric 1626980Seric /* find current place in list -- keep back pointer? */ 1636980Seric for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link) 1646980Seric { 1656980Seric if (strcmp(field, h->h_field) == 0) 1666980Seric break; 1676980Seric } 1686980Seric 1696980Seric /* allocate space for new header */ 1706980Seric h = (HDR *) xalloc(sizeof *h); 1716980Seric h->h_field = field; 1726980Seric h->h_value = newstr(value); 1737368Seric h->h_link = *hp; 1746980Seric h->h_flags = hi->hi_flags | H_DEFAULT; 1756980Seric h->h_mflags = hi->hi_mflags; 1766980Seric *hp = h; 1776980Seric } 1786980Seric /* 1794091Seric ** HVALUE -- return value of a header. 1804091Seric ** 1814091Seric ** Only "real" fields (i.e., ones that have not been supplied 1824091Seric ** as a default) are used. 1834091Seric ** 1844091Seric ** Parameters: 1854091Seric ** field -- the field name. 1864091Seric ** 1874091Seric ** Returns: 1884091Seric ** pointer to the value part. 1894091Seric ** NULL if not found. 1904091Seric ** 1914091Seric ** Side Effects: 1924091Seric ** sets the H_USED bit in the header if found. 1934091Seric */ 1944091Seric 1954091Seric char * 1964091Seric hvalue(field) 1974091Seric char *field; 1984091Seric { 1994091Seric register HDR *h; 2004091Seric 2016908Seric for (h = CurEnv->e_header; h != NULL; h = h->h_link) 2024091Seric { 2034091Seric if (!bitset(H_DEFAULT, h->h_flags) && strcmp(h->h_field, field) == 0) 2044091Seric { 2054091Seric h->h_flags |= H_USED; 2064091Seric return (h->h_value); 2074091Seric } 2084091Seric } 2094091Seric return (NULL); 2104091Seric } 2114091Seric /* 2127677Seric ** HRVALUE -- return pointer to header descriptor. 2137677Seric ** 2147677Seric ** Like hvalue except returns header descriptor block and isn't 2157677Seric ** picky about "real" headers. 2167677Seric ** 2177677Seric ** Parameters: 2187677Seric ** field -- name of field we are interested in. 2197677Seric ** 2207677Seric ** Returns: 2217677Seric ** pointer to header descriptor. 2227677Seric ** 2237677Seric ** Side Effects: 2247677Seric ** none. 2257677Seric */ 2267677Seric 2277677Seric HDR * 2287677Seric hrvalue(field) 2297677Seric char *field; 2307677Seric { 2317677Seric register HDR *h; 2327677Seric 2337677Seric for (h = CurEnv->e_header; h != NULL; h = h->h_link) 2347677Seric { 2357677Seric if (strcmp(h->h_field, field) == 0) 2367677Seric return (h); 2377677Seric } 2387677Seric return (NULL); 2397677Seric } 2407677Seric /* 2414091Seric ** ISHEADER -- predicate telling if argument is a header. 2424091Seric ** 2434319Seric ** A line is a header if it has a single word followed by 2444319Seric ** optional white space followed by a colon. 2454319Seric ** 2464091Seric ** Parameters: 2474091Seric ** s -- string to check for possible headerness. 2484091Seric ** 2494091Seric ** Returns: 2504091Seric ** TRUE if s is a header. 2514091Seric ** FALSE otherwise. 2524091Seric ** 2534091Seric ** Side Effects: 2544091Seric ** none. 2554091Seric */ 2564091Seric 2574091Seric bool 2584091Seric isheader(s) 2594091Seric register char *s; 2604091Seric { 2614091Seric if (!isalnum(*s)) 2624091Seric return (FALSE); 2637855Seric while (!isspace(*s) && *s != ':' && *s != '\0') 2644091Seric s++; 2654091Seric while (isspace(*s)) 2664091Seric s++; 2674091Seric return (*s == ':'); 2684091Seric } 2695919Seric /* 2705919Seric ** GETXPART -- extract the "signature" part of an address line. 2715919Seric ** 2725919Seric ** Try to extract the full name from a general address 2735919Seric ** field. We take anything which is a comment as a 2745919Seric ** first choice. Failing in that, we see if there is 2755919Seric ** a "machine readable" name (in <angle brackets>); if 2765919Seric ** so we take anything preceeding that clause. 2775919Seric ** 2785919Seric ** If we blow it here it's not all that serious. 2795919Seric ** 2805919Seric ** Parameters: 2815919Seric ** p -- line to crack. 2825919Seric ** 2835919Seric ** Returns: 2845919Seric ** signature part. 2855919Seric ** NULL if no signature part. 2865919Seric ** 2875919Seric ** Side Effects: 2885919Seric ** none. 2895919Seric */ 2905919Seric 2915919Seric char * 2925919Seric getxpart(p) 2935919Seric register char *p; 2945919Seric { 2955919Seric register char *q; 2965919Seric register char *rval = NULL; 2975919Seric 2985919Seric q = index(p, '('); 2995919Seric if (q != NULL) 3005919Seric { 3015919Seric int parenlev = 0; 3025919Seric 3035919Seric for (p = q; *p != '\0'; p++) 3045919Seric { 3055919Seric if (*p == '(') 3065919Seric parenlev++; 3075919Seric else if (*p == ')' && --parenlev <= 0) 3085919Seric break; 3095919Seric } 3105919Seric if (*p == ')') 3115919Seric { 3125919Seric *p = '\0'; 3135919Seric if (*++q != '\0') 3145919Seric rval = newstr(q); 3155919Seric *p = ')'; 3165919Seric } 3175919Seric } 3185919Seric else if ((q = index(p, '<')) != NULL) 3195919Seric { 3205919Seric char savec; 3215919Seric 3225919Seric while (*--q == ' ') 3235919Seric continue; 3245919Seric while (isspace(*p)) 3255919Seric p++; 3265919Seric savec = *++q; 3275919Seric *q = '\0'; 3285919Seric if (*p != '\0') 3295919Seric rval = newstr(p); 3305919Seric *q = savec; 3315919Seric } 3325919Seric 3335919Seric return (rval); 3345919Seric } 3357783Seric /* 3367783Seric ** EATHEADER -- run through the stored header and extract info. 3377783Seric ** 3387783Seric ** Parameters: 3397783Seric ** none. 3407783Seric ** 3417783Seric ** Returns: 3427783Seric ** none. 3437783Seric ** 3447783Seric ** Side Effects: 3457783Seric ** Sets a bunch of global variables from information 3467783Seric ** in the collected header. 3477783Seric */ 3487783Seric 3497783Seric eatheader() 3507783Seric { 3517783Seric register HDR *h; 3527783Seric register char *p; 3537783Seric char buf[MAXLINE]; 3547783Seric 3557783Seric # ifdef DEBUG 3567783Seric if (tTd(32, 2)) 3577783Seric { 3587783Seric extern char *capitalize(); 3597783Seric 3607783Seric printf("----- collected header -----\n"); 3617783Seric for (h = CurEnv->e_header; h != NULL; h = h->h_link) 3627783Seric printf("%s: %s\n", capitalize(h->h_field), h->h_value); 3637783Seric printf("----------------------------\n"); 3647783Seric } 3657783Seric # endif DEBUG 3667783Seric 3677783Seric /* message priority */ 3687783Seric if (!QueueRun) 3697783Seric { 3707783Seric /* adjust total priority by message priority */ 3717783Seric CurEnv->e_msgpriority = CurEnv->e_msgsize; 3728066Seric p = hvalue("precedence"); 3737783Seric if (p != NULL) 3747783Seric CurEnv->e_class = priencode(p); 3757783Seric else 3767783Seric CurEnv->e_class = PRI_NORMAL; 3777783Seric CurEnv->e_msgpriority -= CurEnv->e_class * WKPRIFACT; 3787783Seric } 3797783Seric 3808066Seric /* return receipt to */ 3818066Seric p = hvalue("return-receipt-to"); 3827783Seric if (p != NULL) 3838066Seric CurEnv->e_receiptto = p; 3847783Seric 3857783Seric /* from person */ 3867783Seric if (ArpaMode) 3878066Seric { 3888066Seric register struct hdrinfo *hi = HdrInfo; 3897783Seric 3908066Seric for (p = NULL; p == NULL && hi->hi_field != NULL; hi++) 3918066Seric { 3928066Seric if (bitset(H_FROM, hi->hi_flags)) 3938066Seric p = hvalue(hi->hi_field); 3948066Seric } 3958066Seric if (p != NULL) 3968066Seric setfrom(p, (char *) NULL); 3978066Seric } 3988066Seric 3997783Seric /* full name of from person */ 4007783Seric p = hvalue("full-name"); 4017783Seric if (p != NULL) 4027783Seric define('x', p); 4037783Seric 4047783Seric /* date message originated */ 4057783Seric p = hvalue("posted-date"); 4067783Seric if (p == NULL) 4077783Seric p = hvalue("date"); 4087783Seric if (p != NULL) 4097783Seric { 4107783Seric define('a', p); 4117783Seric /* we don't have a good way to do canonical conversion .... 4127783Seric define('d', newstr(arpatounix(p))); 4137783Seric .... so we will ignore the problem for the time being */ 4147783Seric } 4157783Seric } 4167783Seric /* 4177783Seric ** PRIENCODE -- encode external priority names into internal values. 4187783Seric ** 4197783Seric ** Parameters: 4207783Seric ** p -- priority in ascii. 4217783Seric ** 4227783Seric ** Returns: 4237783Seric ** priority as a numeric level. 4247783Seric ** 4257783Seric ** Side Effects: 4267783Seric ** none. 4277783Seric */ 4287783Seric 4297783Seric struct prio 4307783Seric { 4317783Seric char *pri_name; /* external name of priority */ 4327783Seric int pri_val; /* internal value for same */ 4337783Seric }; 4347783Seric 4357783Seric static struct prio Prio[] = 4367783Seric { 4377783Seric "alert", PRI_ALERT, 4387783Seric "quick", PRI_QUICK, 4397783Seric "first-class", PRI_FIRSTCL, 4407783Seric "normal", PRI_NORMAL, 4417783Seric "second-class", PRI_SECONDCL, 4427783Seric "third-class", PRI_THIRDCL, 4437783Seric "junk", PRI_JUNK, 4447783Seric NULL, PRI_NORMAL, 4457783Seric }; 4467783Seric 4477783Seric priencode(p) 4487783Seric char *p; 4497783Seric { 4507783Seric register struct prio *pl; 4517783Seric extern bool sameword(); 4527783Seric 4537783Seric for (pl = Prio; pl->pri_name != NULL; pl++) 4547783Seric { 4557783Seric if (sameword(p, pl->pri_name)) 4567783Seric break; 4577783Seric } 4587783Seric return (pl->pri_val); 4597783Seric } 4607783Seric /* 4617890Seric ** CRACKADDR -- parse an address and turn it into a macro 4627783Seric ** 4637783Seric ** This doesn't actually parse the address -- it just extracts 4647783Seric ** it and replaces it with "$g". The parse is totally ad hoc 4657783Seric ** and isn't even guaranteed to leave something syntactically 4667783Seric ** identical to what it started with. However, it does leave 4677783Seric ** something semantically identical. 4687783Seric ** 4697783Seric ** The process is kind of strange. There are a number of 4707783Seric ** interesting cases: 4717783Seric ** 1. comment <address> comment ==> comment <$g> comment 4727783Seric ** 2. address ==> address 4737783Seric ** 3. address (comment) ==> $g (comment) 4747783Seric ** 4. (comment) address ==> (comment) $g 4757783Seric ** And then there are the hard cases.... 4767783Seric ** 5. add (comment) ress ==> $g (comment) 4777783Seric ** 6. comment <address (comment)> ==> comment <$g (comment)> 4787783Seric ** 7. .... etc .... 4797783Seric ** 4807783Seric ** Parameters: 4817890Seric ** addr -- the address to be cracked. 4827783Seric ** 4837783Seric ** Returns: 4847783Seric ** a pointer to the new version. 4857783Seric ** 4867783Seric ** Side Effects: 4877890Seric ** none. 4887783Seric ** 4897783Seric ** Warning: 4907783Seric ** The return value is saved in local storage and should 4917783Seric ** be copied if it is to be reused. 4927783Seric */ 4937783Seric 4947783Seric char * 4957890Seric crackaddr(addr) 4967890Seric register char *addr; 4977783Seric { 4987783Seric register char *p; 4997783Seric register int i; 5007783Seric static char buf[MAXNAME]; 5017783Seric char *rhs; 5027783Seric bool gotaddr; 5037783Seric register char *bp; 5047783Seric 5057783Seric # ifdef DEBUG 5067783Seric if (tTd(33, 1)) 5077890Seric printf("crackaddr(%s)\n", addr); 5087783Seric # endif DEBUG 5097783Seric 5107783Seric strcpy(buf, ""); 5117783Seric rhs = NULL; 5127783Seric 5138082Seric /* strip leading spaces */ 5148082Seric while (*addr != '\0' && isspace(*addr)) 5158082Seric addr++; 5168082Seric 5177783Seric /* 5187783Seric ** See if we have anything in angle brackets. If so, that is 5197783Seric ** the address part, and the rest is the comment. 5207783Seric */ 5217783Seric 5227890Seric p = index(addr, '<'); 5237783Seric if (p != NULL) 5247783Seric { 5257890Seric /* copy the beginning of the addr field to the buffer */ 5267783Seric *p = '\0'; 5277890Seric strcpy(buf, addr); 5287783Seric strcat(buf, "<"); 5298082Seric *p++ = '<'; 5307783Seric 5318082Seric /* skip spaces */ 5328082Seric while (isspace(*p)) 5338082Seric p++; 5348082Seric 5357783Seric /* find the matching right angle bracket */ 5368082Seric addr = p; 5377783Seric for (i = 0; *p != '\0'; p++) 5387783Seric { 5397783Seric switch (*p) 5407783Seric { 5417783Seric case '<': 5427783Seric i++; 5437783Seric break; 5447783Seric 5457783Seric case '>': 5467783Seric i--; 5477783Seric break; 5487783Seric } 5497783Seric if (i < 0) 5507783Seric break; 5517783Seric } 5527783Seric 5537783Seric /* p now points to the closing quote (or a null byte) */ 5547783Seric if (*p != '\0') 5557783Seric { 5567783Seric /* make rhs point to the extra stuff at the end */ 5577783Seric rhs = p; 5587783Seric *p++ = '\0'; 5597783Seric } 5607783Seric } 5617783Seric 5627783Seric /* 5637944Seric ** Now parse the real address part. "addr" points to the (null 5647783Seric ** terminated) version of what we are inerested in; rhs points 5657783Seric ** to the extra stuff at the end of the line, if any. 5667783Seric */ 5677783Seric 5687890Seric p = addr; 5697783Seric 5707783Seric /* now strip out comments */ 5717783Seric bp = &buf[strlen(buf)]; 5727783Seric gotaddr = FALSE; 5737783Seric for (; *p != '\0'; p++) 5747783Seric { 5757783Seric if (*p == '(') 5767783Seric { 5777783Seric /* copy to matching close paren */ 5787783Seric *bp++ = *p++; 5797783Seric for (i = 0; *p != '\0'; p++) 5807783Seric { 5817783Seric *bp++ = *p; 5827783Seric switch (*p) 5837783Seric { 5847783Seric case '(': 5857783Seric i++; 5867783Seric break; 5877783Seric 5887783Seric case ')': 5897783Seric i--; 5907783Seric break; 5917783Seric } 5927783Seric if (i < 0) 5937783Seric break; 5947783Seric } 5957783Seric continue; 5967783Seric } 5977783Seric 5987783Seric /* 5997783Seric ** If this is the first "real" character we have seen, 6007783Seric ** then we put the "$g" in the buffer now. 6017783Seric */ 6027783Seric 6037783Seric if (isspace(*p)) 6047783Seric *bp++ = *p; 6057783Seric else if (!gotaddr) 6067783Seric { 6077783Seric strcpy(bp, "$g"); 6087783Seric bp += 2; 6097783Seric gotaddr = TRUE; 6107783Seric } 6117783Seric } 6127783Seric 6137944Seric /* hack, hack.... strip trailing blanks */ 6147944Seric do 6157944Seric { 6167944Seric *bp-- = '\0'; 6177944Seric } while (isspace(*bp)); 6187944Seric bp++; 6197783Seric 6207944Seric /* put any right hand side back on */ 6217783Seric if (rhs != NULL) 6227783Seric { 6237783Seric *rhs = '>'; 6247783Seric strcpy(bp, rhs); 6257783Seric } 6267783Seric 6277783Seric # ifdef DEBUG 6287783Seric if (tTd(33, 1)) 6297944Seric printf("crackaddr=>`%s'\n", buf); 6307783Seric # endif DEBUG 6317783Seric 6327783Seric return (buf); 6337783Seric } 634