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