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