1 # include <errno.h> 2 # include "sendmail.h" 3 4 SCCSID(@(#)headers.c 3.16 02/22/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 && strcmp(fname, "from") == 0) 75 { 76 OrigFrom = newstr(fvalue); 77 return (0); 78 } 79 80 /* search header list for this header */ 81 for (hp = &Header, h = 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, &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 OldStyle = FALSE; 129 130 return (h->h_flags); 131 } 132 /* 133 ** HVALUE -- return value of a header. 134 ** 135 ** Only "real" fields (i.e., ones that have not been supplied 136 ** as a default) are used. 137 ** 138 ** Parameters: 139 ** field -- the field name. 140 ** 141 ** Returns: 142 ** pointer to the value part. 143 ** NULL if not found. 144 ** 145 ** Side Effects: 146 ** sets the H_USED bit in the header if found. 147 */ 148 149 char * 150 hvalue(field) 151 char *field; 152 { 153 register HDR *h; 154 155 for (h = Header; h != NULL; h = h->h_link) 156 { 157 if (!bitset(H_DEFAULT, h->h_flags) && strcmp(h->h_field, field) == 0) 158 { 159 h->h_flags |= H_USED; 160 return (h->h_value); 161 } 162 } 163 return (NULL); 164 } 165 /* 166 ** ISHEADER -- predicate telling if argument is a header. 167 ** 168 ** A line is a header if it has a single word followed by 169 ** optional white space followed by a colon. 170 ** 171 ** Parameters: 172 ** s -- string to check for possible headerness. 173 ** 174 ** Returns: 175 ** TRUE if s is a header. 176 ** FALSE otherwise. 177 ** 178 ** Side Effects: 179 ** none. 180 ** 181 ** Bugs: 182 ** According to RFC733, there should be a newline 183 ** permitted after the word but before the colon. 184 ** We don't seem to support that..... 185 */ 186 187 bool 188 isheader(s) 189 register char *s; 190 { 191 if (!isalnum(*s)) 192 return (FALSE); 193 while (!isspace(*s) && *s != ':') 194 s++; 195 while (isspace(*s)) 196 s++; 197 return (*s == ':'); 198 } 199 /* 200 ** GETXPART -- extract the "signature" part of an address line. 201 ** 202 ** Try to extract the full name from a general address 203 ** field. We take anything which is a comment as a 204 ** first choice. Failing in that, we see if there is 205 ** a "machine readable" name (in <angle brackets>); if 206 ** so we take anything preceeding that clause. 207 ** 208 ** If we blow it here it's not all that serious. 209 ** 210 ** Parameters: 211 ** p -- line to crack. 212 ** 213 ** Returns: 214 ** signature part. 215 ** NULL if no signature part. 216 ** 217 ** Side Effects: 218 ** none. 219 */ 220 221 char * 222 getxpart(p) 223 register char *p; 224 { 225 register char *q; 226 register char *rval = NULL; 227 228 q = index(p, '('); 229 if (q != NULL) 230 { 231 int parenlev = 0; 232 233 for (p = q; *p != '\0'; p++) 234 { 235 if (*p == '(') 236 parenlev++; 237 else if (*p == ')' && --parenlev <= 0) 238 break; 239 } 240 if (*p == ')') 241 { 242 *p = '\0'; 243 if (*++q != '\0') 244 rval = newstr(q); 245 *p = ')'; 246 } 247 } 248 else if ((q = index(p, '<')) != NULL) 249 { 250 char savec; 251 252 while (*--q == ' ') 253 continue; 254 while (isspace(*p)) 255 p++; 256 savec = *++q; 257 *q = '\0'; 258 if (*p != '\0') 259 rval = newstr(p); 260 *q = savec; 261 } 262 263 return (rval); 264 } 265