1 # include <errno.h> 2 # include "sendmail.h" 3 4 SCCSID(@(#)headers.c 3.23 08/15/82); 5 6 /* 7 ** CHOMPHEADER -- process and save a header line. 8 ** 9 ** Called by collect and by readcf to deal with header lines. 10 ** 11 ** Parameters: 12 ** line -- header as a text line. 13 ** def -- if set, this is a default value. 14 ** 15 ** Returns: 16 ** flags for this header. 17 ** 18 ** Side Effects: 19 ** The header is saved on the header list. 20 ** Contents of 'line' are destroyed. 21 */ 22 23 chompheader(line, def) 24 char *line; 25 bool def; 26 { 27 register char *p; 28 register HDR *h; 29 HDR **hp; 30 extern bool isheader(); 31 char *fname; 32 char *fvalue; 33 struct hdrinfo *hi; 34 u_long mopts; 35 extern u_long mfencode(); 36 37 # ifdef DEBUG 38 if (tTd(31, 6)) 39 printf("chompheader: %s\n", line); 40 # endif DEBUG 41 42 /* strip off trailing newline */ 43 p = rindex(line, '\n'); 44 if (p != NULL) 45 *p = '\0'; 46 47 /* strip off options */ 48 mopts = 0; 49 p = line; 50 if (*p == '?') 51 { 52 /* have some */ 53 register char *q = index(p + 1, *p); 54 55 if (q != NULL) 56 { 57 *q++ = '\0'; 58 mopts = mfencode(p + 1); 59 p = q; 60 } 61 else 62 syserr("chompheader: syntax error, line \"%s\"", line); 63 } 64 65 /* find canonical name */ 66 fname = p; 67 p = index(p, ':'); 68 fvalue = &p[1]; 69 while (isspace(*--p)) 70 continue; 71 *++p = '\0'; 72 makelower(fname); 73 74 /* strip field value on front */ 75 if (*fvalue == ' ') 76 fvalue++; 77 78 /* hack, hack -- save From: line specially */ 79 if (!def && strcmp(fname, "from") == 0) 80 { 81 CurEnv->e_origfrom = newstr(fvalue); 82 return (0); 83 } 84 85 /* search header list for this header */ 86 for (hp = &CurEnv->e_header, h = CurEnv->e_header; h != NULL; hp = &h->h_link, h = h->h_link) 87 { 88 if (strcmp(fname, h->h_field) == 0 && bitset(H_DEFAULT, h->h_flags)) 89 break; 90 } 91 92 /* see if it is a known type */ 93 for (hi = HdrInfo; hi->hi_field != NULL; hi++) 94 { 95 if (strcmp(hi->hi_field, fname) == 0) 96 break; 97 } 98 99 /* if this means "end of header" quit now */ 100 if (bitset(H_EOH, hi->hi_flags)) 101 return (hi->hi_flags); 102 103 /* count Mail-From: lines to avoid loops (simulate hop counts) */ 104 if (strcmp(fname, "mail-from") == 0) 105 HopCount++; 106 107 /* create/fill in a new node */ 108 if (h == NULL || bitset(H_FORCE, h->h_flags)) 109 { 110 /* create a new node */ 111 h = (HDR *) xalloc(sizeof *h); 112 h->h_field = newstr(fname); 113 h->h_value = NULL; 114 h->h_link = *hp; 115 h->h_flags = hi->hi_flags; 116 h->h_mflags = mopts | hi->hi_mflags; 117 *hp = h; 118 } 119 if (def) 120 h->h_flags |= H_DEFAULT; 121 else if (mopts == 0) 122 h->h_flags &= ~H_CHECK; 123 if (h->h_value != NULL) 124 free(h->h_value); 125 h->h_value = newstr(fvalue); 126 if (!def && GrabTo && bitset(H_RCPT, h->h_flags)) 127 sendto(h->h_value, 0, (ADDRESS *) NULL, &CurEnv->e_sendqueue); 128 129 /* hack to see if this is a new format message */ 130 if (bitset(H_RCPT, h->h_flags) && 131 (index(fvalue, ',') != NULL || index(fvalue, '(') != NULL || 132 index(fvalue, '<') != NULL)) 133 CurEnv->e_oldstyle = FALSE; 134 135 return (h->h_flags); 136 } 137 /* 138 ** ADDHEADER -- add a header entry to the end of the queue. 139 ** 140 ** This bypasses the special checking of chompheader. 141 ** 142 ** Parameters: 143 ** field -- the name of the header field. 144 ** value -- the value of the field. It must be lower-cased. 145 ** e -- the envelope to add them to. 146 ** 147 ** Returns: 148 ** none. 149 ** 150 ** Side Effects: 151 ** adds the field on the list of headers for this envelope. 152 */ 153 154 addheader(field, value, e) 155 char *field; 156 char *value; 157 ENVELOPE *e; 158 { 159 register HDR *h; 160 register struct hdrinfo *hi; 161 HDR **hp; 162 163 /* find info struct */ 164 for (hi = HdrInfo; hi->hi_field != NULL; hi++) 165 { 166 if (strcmp(field, hi->hi_field) == 0) 167 break; 168 } 169 170 /* find current place in list -- keep back pointer? */ 171 for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link) 172 { 173 if (strcmp(field, h->h_field) == 0) 174 break; 175 } 176 177 /* allocate space for new header */ 178 h = (HDR *) xalloc(sizeof *h); 179 h->h_field = field; 180 h->h_value = newstr(value); 181 h->h_link = *hp; 182 h->h_flags = hi->hi_flags | H_DEFAULT; 183 h->h_mflags = hi->hi_mflags; 184 *hp = h; 185 } 186 /* 187 ** HVALUE -- return value of a header. 188 ** 189 ** Only "real" fields (i.e., ones that have not been supplied 190 ** as a default) are used. 191 ** 192 ** Parameters: 193 ** field -- the field name. 194 ** 195 ** Returns: 196 ** pointer to the value part. 197 ** NULL if not found. 198 ** 199 ** Side Effects: 200 ** sets the H_USED bit in the header if found. 201 */ 202 203 char * 204 hvalue(field) 205 char *field; 206 { 207 register HDR *h; 208 209 for (h = CurEnv->e_header; h != NULL; h = h->h_link) 210 { 211 if (!bitset(H_DEFAULT, h->h_flags) && strcmp(h->h_field, field) == 0) 212 { 213 h->h_flags |= H_USED; 214 return (h->h_value); 215 } 216 } 217 return (NULL); 218 } 219 /* 220 ** HRVALUE -- return pointer to header descriptor. 221 ** 222 ** Like hvalue except returns header descriptor block and isn't 223 ** picky about "real" headers. 224 ** 225 ** Parameters: 226 ** field -- name of field we are interested in. 227 ** 228 ** Returns: 229 ** pointer to header descriptor. 230 ** 231 ** Side Effects: 232 ** none. 233 */ 234 235 HDR * 236 hrvalue(field) 237 char *field; 238 { 239 register HDR *h; 240 241 for (h = CurEnv->e_header; h != NULL; h = h->h_link) 242 { 243 if (strcmp(h->h_field, field) == 0) 244 return (h); 245 } 246 return (NULL); 247 } 248 /* 249 ** ISHEADER -- predicate telling if argument is a header. 250 ** 251 ** A line is a header if it has a single word followed by 252 ** optional white space followed by a colon. 253 ** 254 ** Parameters: 255 ** s -- string to check for possible headerness. 256 ** 257 ** Returns: 258 ** TRUE if s is a header. 259 ** FALSE otherwise. 260 ** 261 ** Side Effects: 262 ** none. 263 ** 264 ** Bugs: 265 ** According to RFC733, there should be a newline 266 ** permitted after the word but before the colon. 267 ** We don't seem to support that..... 268 */ 269 270 bool 271 isheader(s) 272 register char *s; 273 { 274 if (!isalnum(*s)) 275 return (FALSE); 276 while (!isspace(*s) && *s != ':') 277 s++; 278 while (isspace(*s)) 279 s++; 280 return (*s == ':'); 281 } 282 /* 283 ** GETXPART -- extract the "signature" part of an address line. 284 ** 285 ** Try to extract the full name from a general address 286 ** field. We take anything which is a comment as a 287 ** first choice. Failing in that, we see if there is 288 ** a "machine readable" name (in <angle brackets>); if 289 ** so we take anything preceeding that clause. 290 ** 291 ** If we blow it here it's not all that serious. 292 ** 293 ** Parameters: 294 ** p -- line to crack. 295 ** 296 ** Returns: 297 ** signature part. 298 ** NULL if no signature part. 299 ** 300 ** Side Effects: 301 ** none. 302 */ 303 304 char * 305 getxpart(p) 306 register char *p; 307 { 308 register char *q; 309 register char *rval = NULL; 310 311 q = index(p, '('); 312 if (q != NULL) 313 { 314 int parenlev = 0; 315 316 for (p = q; *p != '\0'; p++) 317 { 318 if (*p == '(') 319 parenlev++; 320 else if (*p == ')' && --parenlev <= 0) 321 break; 322 } 323 if (*p == ')') 324 { 325 *p = '\0'; 326 if (*++q != '\0') 327 rval = newstr(q); 328 *p = ')'; 329 } 330 } 331 else if ((q = index(p, '<')) != NULL) 332 { 333 char savec; 334 335 while (*--q == ' ') 336 continue; 337 while (isspace(*p)) 338 p++; 339 savec = *++q; 340 *q = '\0'; 341 if (*p != '\0') 342 rval = newstr(p); 343 *q = savec; 344 } 345 346 return (rval); 347 } 348