1 # include <errno.h> 2 # include "sendmail.h" 3 4 SCCSID(@(#)headers.c 3.22 08/08/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 && !QueueRun && 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 /* don't put timestamps in every queue run */ 104 if (QueueRun && h != NULL && bitset(H_FORCE, h->h_flags)) 105 return (h->h_flags); 106 107 /* count Mail-From: lines to avoid loops (simulate hop counts) */ 108 if (strcmp(fname, "mail-from") == 0) 109 HopCount++; 110 111 /* create/fill in a new node */ 112 if (h == NULL || bitset(H_FORCE, h->h_flags)) 113 { 114 /* create a new node */ 115 h = (HDR *) xalloc(sizeof *h); 116 h->h_field = newstr(fname); 117 h->h_value = NULL; 118 h->h_link = *hp; 119 h->h_flags = hi->hi_flags; 120 h->h_mflags = mopts | hi->hi_mflags; 121 *hp = h; 122 } 123 if (def) 124 h->h_flags |= H_DEFAULT; 125 else if (mopts == 0) 126 h->h_flags &= ~H_CHECK; 127 if (h->h_value != NULL) 128 free(h->h_value); 129 h->h_value = newstr(fvalue); 130 if (!def && GrabTo && bitset(H_RCPT, h->h_flags)) 131 sendto(h->h_value, 0, (ADDRESS *) NULL, &CurEnv->e_sendqueue); 132 133 /* hack to see if this is a new format message */ 134 if (bitset(H_RCPT, h->h_flags) && 135 (index(fvalue, ',') != NULL || index(fvalue, '(') != NULL || 136 index(fvalue, '<') != NULL)) 137 CurEnv->e_oldstyle = FALSE; 138 139 return (h->h_flags); 140 } 141 /* 142 ** ADDHEADER -- add a header entry to the end of the queue. 143 ** 144 ** This bypasses the special checking of chompheader. 145 ** 146 ** Parameters: 147 ** field -- the name of the header field. 148 ** value -- the value of the field. It must be lower-cased. 149 ** e -- the envelope to add them to. 150 ** 151 ** Returns: 152 ** none. 153 ** 154 ** Side Effects: 155 ** adds the field on the list of headers for this envelope. 156 */ 157 158 addheader(field, value, e) 159 char *field; 160 char *value; 161 ENVELOPE *e; 162 { 163 register HDR *h; 164 register struct hdrinfo *hi; 165 HDR **hp; 166 167 /* find info struct */ 168 for (hi = HdrInfo; hi->hi_field != NULL; hi++) 169 { 170 if (strcmp(field, hi->hi_field) == 0) 171 break; 172 } 173 174 /* find current place in list -- keep back pointer? */ 175 for (hp = &e->e_header; (h = *hp) != NULL; hp = &h->h_link) 176 { 177 if (strcmp(field, h->h_field) == 0) 178 break; 179 } 180 181 /* allocate space for new header */ 182 h = (HDR *) xalloc(sizeof *h); 183 h->h_field = field; 184 h->h_value = newstr(value); 185 h->h_link = *hp; 186 h->h_flags = hi->hi_flags | H_DEFAULT; 187 h->h_mflags = hi->hi_mflags; 188 *hp = h; 189 } 190 /* 191 ** HVALUE -- return value of a header. 192 ** 193 ** Only "real" fields (i.e., ones that have not been supplied 194 ** as a default) are used. 195 ** 196 ** Parameters: 197 ** field -- the field name. 198 ** 199 ** Returns: 200 ** pointer to the value part. 201 ** NULL if not found. 202 ** 203 ** Side Effects: 204 ** sets the H_USED bit in the header if found. 205 */ 206 207 char * 208 hvalue(field) 209 char *field; 210 { 211 register HDR *h; 212 213 for (h = CurEnv->e_header; h != NULL; h = h->h_link) 214 { 215 if (!bitset(H_DEFAULT, h->h_flags) && strcmp(h->h_field, field) == 0) 216 { 217 h->h_flags |= H_USED; 218 return (h->h_value); 219 } 220 } 221 return (NULL); 222 } 223 /* 224 ** HRVALUE -- return pointer to header descriptor. 225 ** 226 ** Like hvalue except returns header descriptor block and isn't 227 ** picky about "real" headers. 228 ** 229 ** Parameters: 230 ** field -- name of field we are interested in. 231 ** 232 ** Returns: 233 ** pointer to header descriptor. 234 ** 235 ** Side Effects: 236 ** none. 237 */ 238 239 HDR * 240 hrvalue(field) 241 char *field; 242 { 243 register HDR *h; 244 245 for (h = CurEnv->e_header; h != NULL; h = h->h_link) 246 { 247 if (strcmp(h->h_field, field) == 0) 248 return (h); 249 } 250 return (NULL); 251 } 252 /* 253 ** ISHEADER -- predicate telling if argument is a header. 254 ** 255 ** A line is a header if it has a single word followed by 256 ** optional white space followed by a colon. 257 ** 258 ** Parameters: 259 ** s -- string to check for possible headerness. 260 ** 261 ** Returns: 262 ** TRUE if s is a header. 263 ** FALSE otherwise. 264 ** 265 ** Side Effects: 266 ** none. 267 ** 268 ** Bugs: 269 ** According to RFC733, there should be a newline 270 ** permitted after the word but before the colon. 271 ** We don't seem to support that..... 272 */ 273 274 bool 275 isheader(s) 276 register char *s; 277 { 278 if (!isalnum(*s)) 279 return (FALSE); 280 while (!isspace(*s) && *s != ':') 281 s++; 282 while (isspace(*s)) 283 s++; 284 return (*s == ':'); 285 } 286 /* 287 ** GETXPART -- extract the "signature" part of an address line. 288 ** 289 ** Try to extract the full name from a general address 290 ** field. We take anything which is a comment as a 291 ** first choice. Failing in that, we see if there is 292 ** a "machine readable" name (in <angle brackets>); if 293 ** so we take anything preceeding that clause. 294 ** 295 ** If we blow it here it's not all that serious. 296 ** 297 ** Parameters: 298 ** p -- line to crack. 299 ** 300 ** Returns: 301 ** signature part. 302 ** NULL if no signature part. 303 ** 304 ** Side Effects: 305 ** none. 306 */ 307 308 char * 309 getxpart(p) 310 register char *p; 311 { 312 register char *q; 313 register char *rval = NULL; 314 315 q = index(p, '('); 316 if (q != NULL) 317 { 318 int parenlev = 0; 319 320 for (p = q; *p != '\0'; p++) 321 { 322 if (*p == '(') 323 parenlev++; 324 else if (*p == ')' && --parenlev <= 0) 325 break; 326 } 327 if (*p == ')') 328 { 329 *p = '\0'; 330 if (*++q != '\0') 331 rval = newstr(q); 332 *p = ')'; 333 } 334 } 335 else if ((q = index(p, '<')) != NULL) 336 { 337 char savec; 338 339 while (*--q == ' ') 340 continue; 341 while (isspace(*p)) 342 p++; 343 savec = *++q; 344 *q = '\0'; 345 if (*p != '\0') 346 rval = newstr(p); 347 *q = savec; 348 } 349 350 return (rval); 351 } 352