Commit | Line | Data |
---|---|---|
b2a81223 | 1 | /* |
792e6158 | 2 | * Copyright (c) 1983, 1995 Eric P. Allman |
eb0bafab KB |
3 | * Copyright (c) 1988, 1993 |
4 | * The Regents of the University of California. All rights reserved. | |
bee79b64 | 5 | * |
417f7a11 | 6 | * %sccs.include.redist.c% |
bee79b64 | 7 | */ |
b2a81223 DF |
8 | |
9 | #ifndef lint | |
a5386d1b | 10 | static char sccsid[] = "@(#)headers.c 8.69 (Berkeley) %G%"; |
bee79b64 | 11 | #endif /* not lint */ |
b2a81223 | 12 | |
f06af564 EA |
13 | # include <errno.h> |
14 | # include "sendmail.h" | |
15 | ||
f06af564 EA |
16 | /* |
17 | ** CHOMPHEADER -- process and save a header line. | |
18 | ** | |
19 | ** Called by collect and by readcf to deal with header lines. | |
20 | ** | |
21 | ** Parameters: | |
22 | ** line -- header as a text line. | |
23 | ** def -- if set, this is a default value. | |
9905202c | 24 | ** hdrp -- a pointer to the place to save the header. |
a4076aed | 25 | ** e -- the envelope including this header. |
f06af564 EA |
26 | ** |
27 | ** Returns: | |
28 | ** flags for this header. | |
29 | ** | |
30 | ** Side Effects: | |
31 | ** The header is saved on the header list. | |
74c5fe7c | 32 | ** Contents of 'line' are destroyed. |
f06af564 EA |
33 | */ |
34 | ||
179d940c | 35 | int |
9905202c | 36 | chompheader(line, def, hdrp, e) |
f06af564 EA |
37 | char *line; |
38 | bool def; | |
9905202c | 39 | HDR **hdrp; |
a4076aed | 40 | register ENVELOPE *e; |
f06af564 EA |
41 | { |
42 | register char *p; | |
43 | register HDR *h; | |
44 | HDR **hp; | |
f06af564 EA |
45 | char *fname; |
46 | char *fvalue; | |
47 | struct hdrinfo *hi; | |
be2fcca9 | 48 | bool cond = FALSE; |
9905202c | 49 | bool headeronly; |
1dbda134 | 50 | BITMAP mopts; |
8446c922 | 51 | char buf[MAXNAME + 1]; |
abae7b2d | 52 | extern ADDRESS *sendto(); |
f06af564 | 53 | |
9678c96d | 54 | if (tTd(31, 6)) |
a44b7a41 EA |
55 | { |
56 | printf("chompheader: "); | |
57 | xputs(line); | |
58 | printf("\n"); | |
59 | } | |
9678c96d | 60 | |
9905202c EA |
61 | headeronly = hdrp != NULL; |
62 | if (!headeronly) | |
63 | hdrp = &e->e_header; | |
64 | ||
ed45aae1 | 65 | /* strip off options */ |
1dbda134 | 66 | clrbitmap(mopts); |
ed45aae1 | 67 | p = line; |
b46fb70f | 68 | if (*p == '?') |
ed45aae1 EA |
69 | { |
70 | /* have some */ | |
f3d8f6d6 | 71 | register char *q = strchr(p + 1, *p); |
ed45aae1 EA |
72 | |
73 | if (q != NULL) | |
74 | { | |
75 | *q++ = '\0'; | |
1dbda134 EA |
76 | while (*++p != '\0') |
77 | setbitn(*p, mopts); | |
ed45aae1 EA |
78 | p = q; |
79 | } | |
80 | else | |
277e9e5e | 81 | syserr("553 header syntax error, line \"%s\"", line); |
be2fcca9 | 82 | cond = TRUE; |
ed45aae1 EA |
83 | } |
84 | ||
f06af564 | 85 | /* find canonical name */ |
ed45aae1 | 86 | fname = p; |
64c7c6da EA |
87 | while (isascii(*p) && isgraph(*p) && *p != ':') |
88 | p++; | |
89 | fvalue = p; | |
90 | while (isascii(*p) && isspace(*p)) | |
91 | p++; | |
db33fce2 | 92 | if (*p++ != ':' || fname == fvalue) |
e90f41e7 | 93 | { |
b6edea3d | 94 | syserr("553 header syntax error, line \"%s\"", line); |
e90f41e7 EA |
95 | return (0); |
96 | } | |
64c7c6da EA |
97 | *fvalue = '\0'; |
98 | fvalue = p; | |
f06af564 EA |
99 | |
100 | /* strip field value on front */ | |
101 | if (*fvalue == ' ') | |
102 | fvalue++; | |
103 | ||
f06af564 EA |
104 | /* see if it is a known type */ |
105 | for (hi = HdrInfo; hi->hi_field != NULL; hi++) | |
106 | { | |
b6919a63 | 107 | if (strcasecmp(hi->hi_field, fname) == 0) |
f06af564 EA |
108 | break; |
109 | } | |
110 | ||
c93a732e EA |
111 | if (tTd(31, 9)) |
112 | { | |
113 | if (hi->hi_field == NULL) | |
114 | printf("no header match\n"); | |
115 | else | |
07e8718d | 116 | printf("header match, hi_flags=%x\n", hi->hi_flags); |
c93a732e EA |
117 | } |
118 | ||
a90807d8 | 119 | /* see if this is a resent message */ |
9905202c | 120 | if (!def && !headeronly && bitset(H_RESENT, hi->hi_flags)) |
a4076aed | 121 | e->e_flags |= EF_RESENT; |
a90807d8 | 122 | |
b7b719e4 | 123 | /* if this is an Errors-To: header keep track of it now */ |
9905202c EA |
124 | if (UseErrorsTo && !def && !headeronly && |
125 | bitset(H_ERRORSTO, hi->hi_flags)) | |
b7b719e4 EA |
126 | (void) sendtolist(fvalue, NULLADDR, &e->e_errorqueue, 0, e); |
127 | ||
f06af564 EA |
128 | /* if this means "end of header" quit now */ |
129 | if (bitset(H_EOH, hi->hi_flags)) | |
130 | return (hi->hi_flags); | |
131 | ||
9791b2da EA |
132 | /* |
133 | ** Drop explicit From: if same as what we would generate. | |
134 | ** This is to make MH (which doesn't always give a full name) | |
135 | ** insert the full name information in all circumstances. | |
136 | */ | |
137 | ||
03963ff1 | 138 | p = "resent-from"; |
a4076aed | 139 | if (!bitset(EF_RESENT, e->e_flags)) |
03963ff1 | 140 | p += 7; |
9905202c EA |
141 | if (!def && !headeronly && !bitset(EF_QUEUERUN, e->e_flags) && |
142 | strcasecmp(fname, p) == 0) | |
a90807d8 | 143 | { |
8e5c6745 EA |
144 | if (tTd(31, 2)) |
145 | { | |
146 | printf("comparing header from (%s) against default (%s or %s)\n", | |
147 | fvalue, e->e_from.q_paddr, e->e_from.q_user); | |
148 | } | |
a4076aed | 149 | if (e->e_from.q_paddr != NULL && |
8e5c6745 EA |
150 | (strcmp(fvalue, e->e_from.q_paddr) == 0 || |
151 | strcmp(fvalue, e->e_from.q_user) == 0)) | |
a90807d8 | 152 | return (hi->hi_flags); |
c6094a3f | 153 | #ifdef MAYBENEXTRELEASE /* XXX UNTESTED XXX UNTESTED XXX UNTESTED XXX */ |
0159023b | 154 | #if USERDB |
c6094a3f EA |
155 | else |
156 | { | |
157 | auto ADDRESS a; | |
158 | char *fancy; | |
05c33454 | 159 | bool oldSuprErrs = SuprErrs; |
c6094a3f EA |
160 | extern char *crackaddr(); |
161 | extern char *udbsender(); | |
162 | ||
9791b2da EA |
163 | /* |
164 | ** Try doing USERDB rewriting even on fully commented | |
165 | ** names; this saves the "comment" information (such | |
166 | ** as full name) and rewrites the electronic part. | |
0c35528d EA |
167 | ** |
168 | ** XXX This code doesn't belong here -- parsing should | |
169 | ** XXX not be done during collect() phase because | |
170 | ** XXX error messages can confuse the SMTP phase. | |
05c33454 | 171 | ** XXX Setting SuprErrs is a crude hack around this |
0c35528d | 172 | ** XXX problem. |
9791b2da EA |
173 | */ |
174 | ||
0c35528d | 175 | if (OpMode == MD_SMTP || OpMode == MD_ARPAFTP) |
05c33454 | 176 | SuprErrs = TRUE; |
c6094a3f EA |
177 | fancy = crackaddr(fvalue); |
178 | if (parseaddr(fvalue, &a, RF_COPYNONE, '\0', NULL, e) != NULL && | |
2bade550 | 179 | bitnset(M_CHECKUDB, a.q_mailer->m_flags) && |
c6094a3f EA |
180 | (p = udbsender(a.q_user)) != NULL) |
181 | { | |
182 | char *oldg = macvalue('g', e); | |
183 | ||
184 | define('g', p, e); | |
832e8a27 | 185 | expand(fancy, buf, sizeof buf, e); |
c6094a3f EA |
186 | define('g', oldg, e); |
187 | fvalue = buf; | |
188 | } | |
05c33454 | 189 | SuprErrs = oldSuprErrs; |
c6094a3f EA |
190 | } |
191 | #endif | |
192 | #endif | |
03963ff1 EA |
193 | } |
194 | ||
f68d0afc EA |
195 | /* drop forged Sender: values */ |
196 | p = "resent-sender"; | |
197 | if (!bitset(EF_RESENT, CurEnv->e_flags)) | |
198 | p += 7; | |
199 | if (!def && !QueueRun && CurEnv->e_from.q_mailer == LocalMailer && | |
200 | bitset(H_VALID, hi->hi_flags)) | |
201 | { | |
202 | return (hi->hi_flags); | |
203 | } | |
204 | ||
03963ff1 | 205 | /* delete default value for this header */ |
9905202c | 206 | for (hp = hdrp; (h = *hp) != NULL; hp = &h->h_link) |
03963ff1 | 207 | { |
b6919a63 | 208 | if (strcasecmp(fname, h->h_field) == 0 && |
03963ff1 EA |
209 | bitset(H_DEFAULT, h->h_flags) && |
210 | !bitset(H_FORCE, h->h_flags)) | |
e7ebf20a | 211 | { |
03963ff1 | 212 | h->h_value = NULL; |
e7ebf20a EA |
213 | if (!cond) |
214 | { | |
215 | /* copy conditions from default case */ | |
216 | bcopy((char *)h->h_mflags, (char *)mopts, | |
217 | sizeof mopts); | |
218 | } | |
219 | } | |
a90807d8 EA |
220 | } |
221 | ||
7f668477 EA |
222 | /* create a new node */ |
223 | h = (HDR *) xalloc(sizeof *h); | |
224 | h->h_field = newstr(fname); | |
cd3e07da | 225 | h->h_value = newstr(fvalue); |
7f668477 | 226 | h->h_link = NULL; |
17a67c62 | 227 | bcopy((char *) mopts, (char *) h->h_mflags, sizeof mopts); |
7f668477 | 228 | *hp = h; |
fb35a67c | 229 | h->h_flags = hi->hi_flags; |
f06af564 EA |
230 | if (def) |
231 | h->h_flags |= H_DEFAULT; | |
be2fcca9 EA |
232 | if (cond) |
233 | h->h_flags |= H_CHECK; | |
abae7b2d | 234 | (void) sendto(h->h_value, 0, (ADDRESS *) NULL, 0); |
f06af564 | 235 | |
3df53d78 | 236 | /* hack to see if this is a new format message */ |
9905202c | 237 | if (!def && !headeronly && bitset(H_RCPT|H_FROM, h->h_flags) && |
f3d8f6d6 EA |
238 | (strchr(fvalue, ',') != NULL || strchr(fvalue, '(') != NULL || |
239 | strchr(fvalue, '<') != NULL || strchr(fvalue, ';') != NULL)) | |
9ed29988 | 240 | { |
a4076aed | 241 | e->e_flags &= ~EF_OLDSTYLE; |
9ed29988 | 242 | } |
3df53d78 | 243 | |
f06af564 EA |
244 | return (h->h_flags); |
245 | } | |
246 | \f/* | |
dd1fe05b EA |
247 | ** ADDHEADER -- add a header entry to the end of the queue. |
248 | ** | |
249 | ** This bypasses the special checking of chompheader. | |
250 | ** | |
251 | ** Parameters: | |
b6919a63 | 252 | ** field -- the name of the header field. |
94bc039a | 253 | ** value -- the value of the field. |
c23930c0 | 254 | ** hp -- an indirect pointer to the header structure list. |
dd1fe05b EA |
255 | ** |
256 | ** Returns: | |
257 | ** none. | |
258 | ** | |
259 | ** Side Effects: | |
260 | ** adds the field on the list of headers for this envelope. | |
261 | */ | |
262 | ||
179d940c | 263 | void |
c23930c0 | 264 | addheader(field, value, hdrlist) |
dd1fe05b EA |
265 | char *field; |
266 | char *value; | |
c23930c0 | 267 | HDR **hdrlist; |
dd1fe05b EA |
268 | { |
269 | register HDR *h; | |
270 | register struct hdrinfo *hi; | |
271 | HDR **hp; | |
272 | ||
273 | /* find info struct */ | |
274 | for (hi = HdrInfo; hi->hi_field != NULL; hi++) | |
275 | { | |
b6919a63 | 276 | if (strcasecmp(field, hi->hi_field) == 0) |
dd1fe05b EA |
277 | break; |
278 | } | |
279 | ||
280 | /* find current place in list -- keep back pointer? */ | |
c23930c0 | 281 | for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link) |
dd1fe05b | 282 | { |
b6919a63 | 283 | if (strcasecmp(field, h->h_field) == 0) |
dd1fe05b EA |
284 | break; |
285 | } | |
286 | ||
287 | /* allocate space for new header */ | |
288 | h = (HDR *) xalloc(sizeof *h); | |
289 | h->h_field = field; | |
290 | h->h_value = newstr(value); | |
f0375650 | 291 | h->h_link = *hp; |
dd1fe05b | 292 | h->h_flags = hi->hi_flags | H_DEFAULT; |
1dbda134 | 293 | clrbitmap(h->h_mflags); |
dd1fe05b EA |
294 | *hp = h; |
295 | } | |
296 | \f/* | |
f06af564 EA |
297 | ** HVALUE -- return value of a header. |
298 | ** | |
299 | ** Only "real" fields (i.e., ones that have not been supplied | |
300 | ** as a default) are used. | |
301 | ** | |
302 | ** Parameters: | |
303 | ** field -- the field name. | |
c23930c0 | 304 | ** header -- the header list. |
f06af564 EA |
305 | ** |
306 | ** Returns: | |
307 | ** pointer to the value part. | |
308 | ** NULL if not found. | |
309 | ** | |
310 | ** Side Effects: | |
7338e3d4 | 311 | ** none. |
f06af564 EA |
312 | */ |
313 | ||
314 | char * | |
c23930c0 | 315 | hvalue(field, header) |
f06af564 | 316 | char *field; |
c23930c0 | 317 | HDR *header; |
f06af564 EA |
318 | { |
319 | register HDR *h; | |
320 | ||
c23930c0 | 321 | for (h = header; h != NULL; h = h->h_link) |
f06af564 | 322 | { |
b6919a63 EA |
323 | if (!bitset(H_DEFAULT, h->h_flags) && |
324 | strcasecmp(h->h_field, field) == 0) | |
f06af564 | 325 | return (h->h_value); |
f06af564 EA |
326 | } |
327 | return (NULL); | |
328 | } | |
329 | \f/* | |
330 | ** ISHEADER -- predicate telling if argument is a header. | |
331 | ** | |
74c5fe7c EA |
332 | ** A line is a header if it has a single word followed by |
333 | ** optional white space followed by a colon. | |
334 | ** | |
9905202c EA |
335 | ** Header fields beginning with two dashes, although technically |
336 | ** permitted by RFC822, are automatically rejected in order | |
337 | ** to make MIME work out. Without this we could have a technically | |
338 | ** legal header such as ``--"foo:bar"'' that would also be a legal | |
339 | ** MIME separator. | |
340 | ** | |
f06af564 | 341 | ** Parameters: |
277e9e5e | 342 | ** h -- string to check for possible headerness. |
f06af564 EA |
343 | ** |
344 | ** Returns: | |
277e9e5e | 345 | ** TRUE if h is a header. |
f06af564 EA |
346 | ** FALSE otherwise. |
347 | ** | |
348 | ** Side Effects: | |
349 | ** none. | |
350 | */ | |
351 | ||
352 | bool | |
277e9e5e EA |
353 | isheader(h) |
354 | char *h; | |
f06af564 | 355 | { |
277e9e5e EA |
356 | register char *s = h; |
357 | ||
9905202c EA |
358 | if (s[0] == '-' && s[1] == '-') |
359 | return FALSE; | |
360 | ||
7338e3d4 | 361 | while (*s > ' ' && *s != ':' && *s != '\0') |
f06af564 | 362 | s++; |
7338e3d4 | 363 | |
277e9e5e EA |
364 | if (h == s) |
365 | return FALSE; | |
366 | ||
7338e3d4 | 367 | /* following technically violates RFC822 */ |
2bee003d | 368 | while (isascii(*s) && isspace(*s)) |
f06af564 | 369 | s++; |
7338e3d4 | 370 | |
f06af564 EA |
371 | return (*s == ':'); |
372 | } | |
028b97f3 | 373 | \f/* |
75a2bcaf EA |
374 | ** EATHEADER -- run through the stored header and extract info. |
375 | ** | |
376 | ** Parameters: | |
7338e3d4 | 377 | ** e -- the envelope to process. |
959cf51d | 378 | ** full -- if set, do full processing (e.g., compute |
5a6f454c EA |
379 | ** message priority). This should not be set |
380 | ** when reading a queue file because some info | |
381 | ** needed to compute the priority is wrong. | |
75a2bcaf EA |
382 | ** |
383 | ** Returns: | |
384 | ** none. | |
385 | ** | |
386 | ** Side Effects: | |
387 | ** Sets a bunch of global variables from information | |
7338e3d4 EA |
388 | ** in the collected header. |
389 | ** Aborts the message if the hop count is exceeded. | |
75a2bcaf EA |
390 | */ |
391 | ||
179d940c | 392 | void |
959cf51d | 393 | eatheader(e, full) |
7338e3d4 | 394 | register ENVELOPE *e; |
959cf51d | 395 | bool full; |
75a2bcaf EA |
396 | { |
397 | register HDR *h; | |
398 | register char *p; | |
7338e3d4 | 399 | int hopcnt = 0; |
33844dcf | 400 | char *msgid; |
3a848ece EA |
401 | char buf[MAXLINE]; |
402 | ||
403 | /* | |
404 | ** Set up macros for possible expansion in headers. | |
405 | */ | |
406 | ||
4a2da288 EA |
407 | define('f', e->e_sender, e); |
408 | define('g', e->e_sender, e); | |
d4f5b98a EA |
409 | if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0') |
410 | define('u', e->e_origrcpt, e); | |
411 | else | |
412 | define('u', NULL, e); | |
75a2bcaf | 413 | |
908e1c74 | 414 | /* full name of from person */ |
c23930c0 | 415 | p = hvalue("full-name", e->e_header); |
908e1c74 EA |
416 | if (p != NULL) |
417 | define('x', p, e); | |
418 | ||
7338e3d4 EA |
419 | if (tTd(32, 1)) |
420 | printf("----- collected header -----\n"); | |
5a6f454c | 421 | msgid = NULL; |
7338e3d4 | 422 | for (h = e->e_header; h != NULL; h = h->h_link) |
75a2bcaf | 423 | { |
6d8bbe53 EA |
424 | if (tTd(32, 1)) |
425 | printf("%s: ", h->h_field); | |
3b06f2bd EA |
426 | if (h->h_value == NULL) |
427 | { | |
428 | if (tTd(32, 1)) | |
6d8bbe53 | 429 | printf("<NULL>\n"); |
3b06f2bd EA |
430 | continue; |
431 | } | |
432 | ||
3a848ece | 433 | /* do early binding */ |
3b06f2bd | 434 | if (bitset(H_DEFAULT, h->h_flags)) |
3a848ece | 435 | { |
6d8bbe53 EA |
436 | if (tTd(32, 1)) |
437 | { | |
438 | printf("("); | |
439 | xputs(h->h_value); | |
440 | printf(") "); | |
441 | } | |
832e8a27 | 442 | expand(h->h_value, buf, sizeof buf, e); |
3a848ece EA |
443 | if (buf[0] != '\0') |
444 | { | |
3a848ece EA |
445 | h->h_value = newstr(buf); |
446 | h->h_flags &= ~H_DEFAULT; | |
447 | } | |
448 | } | |
449 | ||
7338e3d4 | 450 | if (tTd(32, 1)) |
da9633d1 | 451 | { |
da9633d1 EA |
452 | xputs(h->h_value); |
453 | printf("\n"); | |
454 | } | |
453139c0 | 455 | |
a90807d8 | 456 | /* count the number of times it has been processed */ |
7338e3d4 EA |
457 | if (bitset(H_TRACE, h->h_flags)) |
458 | hopcnt++; | |
a90807d8 EA |
459 | |
460 | /* send to this person if we so desire */ | |
461 | if (GrabTo && bitset(H_RCPT, h->h_flags) && | |
462 | !bitset(H_DEFAULT, h->h_flags) && | |
a4076aed | 463 | (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags))) |
a90807d8 | 464 | { |
d4f6a25e EA |
465 | int saveflags = e->e_flags; |
466 | ||
c93a732e | 467 | (void) sendtolist(h->h_value, NULLADDR, |
f8c2f9fd | 468 | &e->e_sendqueue, 0, e); |
d4f6a25e EA |
469 | |
470 | /* delete fatal errors generated by this address */ | |
d4f5b98a | 471 | if (!GrabTo && !bitset(EF_FATALERRS, saveflags)) |
d4f6a25e | 472 | e->e_flags &= ~EF_FATALERRS; |
a90807d8 EA |
473 | } |
474 | ||
33844dcf | 475 | /* save the message-id for logging */ |
5a6f454c | 476 | if (strcasecmp(h->h_field, "message-id") == 0) |
4e8842eb | 477 | { |
33844dcf | 478 | msgid = h->h_value; |
9f0b3b43 EA |
479 | while (isascii(*msgid) && isspace(*msgid)) |
480 | msgid++; | |
4e8842eb | 481 | } |
453139c0 EA |
482 | |
483 | /* see if this is a return-receipt header */ | |
484 | if (bitset(H_RECEIPTTO, h->h_flags)) | |
485 | e->e_receiptto = h->h_value; | |
75a2bcaf | 486 | } |
7338e3d4 EA |
487 | if (tTd(32, 1)) |
488 | printf("----------------------------\n"); | |
7338e3d4 | 489 | |
9a5a1483 EA |
490 | /* if we are just verifying (that is, sendmail -t -bv), drop out now */ |
491 | if (OpMode == MD_VERIFY) | |
492 | return; | |
493 | ||
7338e3d4 EA |
494 | /* store hop count */ |
495 | if (hopcnt > e->e_hopcount) | |
496 | e->e_hopcount = hopcnt; | |
75a2bcaf | 497 | |
75a2bcaf | 498 | /* message priority */ |
c23930c0 | 499 | p = hvalue("precedence", e->e_header); |
7338e3d4 EA |
500 | if (p != NULL) |
501 | e->e_class = priencode(p); | |
5a6f454c EA |
502 | if (e->e_class < 0) |
503 | e->e_timeoutclass = TOC_NONURGENT; | |
504 | else if (e->e_class > 0) | |
505 | e->e_timeoutclass = TOC_URGENT; | |
959cf51d | 506 | if (full) |
418a3328 | 507 | { |
f746582a | 508 | e->e_msgpriority = e->e_msgsize |
a0225d08 EA |
509 | - e->e_class * WkClassFact |
510 | + e->e_nrcpts * WkRecipFact; | |
418a3328 EA |
511 | } |
512 | ||
513 | /* message timeout priority */ | |
514 | p = hvalue("priority", e->e_header); | |
5a6f454c | 515 | if (p != NULL) |
418a3328 EA |
516 | { |
517 | /* (this should be in the configuration file) */ | |
518 | if (strcasecmp(p, "urgent")) | |
519 | e->e_timeoutclass = TOC_URGENT; | |
520 | else if (strcasecmp(p, "normal")) | |
521 | e->e_timeoutclass = TOC_NORMAL; | |
522 | else if (strcasecmp(p, "non-urgent")) | |
523 | e->e_timeoutclass = TOC_NONURGENT; | |
524 | } | |
75a2bcaf | 525 | |
75a2bcaf | 526 | /* date message originated */ |
c23930c0 | 527 | p = hvalue("posted-date", e->e_header); |
75a2bcaf | 528 | if (p == NULL) |
c23930c0 | 529 | p = hvalue("date", e->e_header); |
75a2bcaf | 530 | if (p != NULL) |
7338e3d4 | 531 | define('a', p, e); |
4e8842eb | 532 | |
923fa8c1 | 533 | /* check to see if this is a MIME message */ |
a5386d1b EA |
534 | else if ((e->e_bodytype != NULL && |
535 | strcasecmp(e->e_bodytype, "8BITMIME") == 0) || | |
536 | hvalue("MIME-Version", e->e_header) != NULL) | |
0b92c6af | 537 | { |
923fa8c1 | 538 | e->e_flags |= EF_IS_MIME; |
0b92c6af EA |
539 | if (HasEightBits) |
540 | e->e_bodytype = "8BITMIME"; | |
541 | } | |
a5386d1b EA |
542 | else if ((p = hvalue("Content-Type", e->e_header)) != NULL) |
543 | { | |
544 | /* this may be an RFC 1049 message */ | |
545 | p = strtok(p, ";/"); | |
546 | if (p == NULL || *p == ';') | |
547 | { | |
548 | /* yep, it is */ | |
549 | e->e_flags |= EF_DONT_MIME; | |
550 | } | |
551 | } | |
923fa8c1 | 552 | |
d940893e EA |
553 | /* |
554 | ** From person in antiquated ARPANET mode | |
555 | ** required by UK Grey Book e-mail gateways (sigh) | |
556 | */ | |
557 | ||
558 | if (OpMode == MD_ARPAFTP) | |
559 | { | |
560 | register struct hdrinfo *hi; | |
561 | ||
562 | for (hi = HdrInfo; hi->hi_field != NULL; hi++) | |
563 | { | |
564 | if (bitset(H_FROM, hi->hi_flags) && | |
565 | (!bitset(H_RESENT, hi->hi_flags) || | |
566 | bitset(EF_RESENT, e->e_flags)) && | |
c23930c0 | 567 | (p = hvalue(hi->hi_field, e->e_header)) != NULL) |
d940893e EA |
568 | break; |
569 | } | |
570 | if (hi->hi_field != NULL) | |
571 | { | |
572 | if (tTd(32, 2)) | |
573 | printf("eatheader: setsender(*%s == %s)\n", | |
574 | hi->hi_field, p); | |
575 | setsender(p, e, NULL, TRUE); | |
576 | } | |
577 | } | |
578 | ||
4e8842eb EA |
579 | /* |
580 | ** Log collection information. | |
581 | */ | |
582 | ||
583 | # ifdef LOG | |
281c6540 | 584 | if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4) |
804e6d6d EA |
585 | logsender(e, msgid); |
586 | # endif /* LOG */ | |
587 | e->e_flags &= ~EF_LOGSENDER; | |
588 | } | |
589 | \f/* | |
590 | ** LOGSENDER -- log sender information | |
591 | ** | |
592 | ** Parameters: | |
593 | ** e -- the envelope to log | |
594 | ** msgid -- the message id | |
595 | ** | |
596 | ** Returns: | |
597 | ** none | |
598 | */ | |
599 | ||
179d940c | 600 | void |
804e6d6d EA |
601 | logsender(e, msgid) |
602 | register ENVELOPE *e; | |
603 | char *msgid; | |
604 | { | |
8b223875 | 605 | # ifdef LOG |
804e6d6d EA |
606 | char *name; |
607 | register char *sbp; | |
608 | register char *p; | |
82d343b5 | 609 | int l; |
8446c922 EA |
610 | char hbuf[MAXNAME + 1]; |
611 | char sbuf[MAXLINE + 1]; | |
612 | char mbuf[MAXNAME + 1]; | |
82d343b5 EA |
613 | |
614 | /* don't allow newlines in the message-id */ | |
615 | if (msgid != NULL) | |
616 | { | |
617 | l = strlen(msgid); | |
618 | if (l > sizeof mbuf - 1) | |
619 | l = sizeof mbuf - 1; | |
620 | bcopy(msgid, mbuf, l); | |
621 | mbuf[l] = '\0'; | |
622 | p = mbuf; | |
623 | while ((p = strchr(p, '\n')) != NULL) | |
624 | *p++ = ' '; | |
625 | } | |
804e6d6d EA |
626 | |
627 | if (bitset(EF_RESPONSE, e->e_flags)) | |
628 | name = "[RESPONSE]"; | |
629 | else if ((name = macvalue('_', e)) != NULL) | |
630 | ; | |
389c0d5e EA |
631 | else if (RealHostName == NULL) |
632 | name = "localhost"; | |
804e6d6d EA |
633 | else if (RealHostName[0] == '[') |
634 | name = RealHostName; | |
635 | else | |
4e8842eb | 636 | { |
804e6d6d EA |
637 | name = hbuf; |
638 | (void) sprintf(hbuf, "%.80s", RealHostName); | |
639 | if (RealHostAddr.sa.sa_family != 0) | |
453139c0 | 640 | { |
804e6d6d EA |
641 | p = &hbuf[strlen(hbuf)]; |
642 | (void) sprintf(p, " (%s)", | |
643 | anynet_ntoa(&RealHostAddr)); | |
453139c0 | 644 | } |
804e6d6d | 645 | } |
453139c0 | 646 | |
804e6d6d | 647 | /* some versions of syslog only take 5 printf args */ |
2bbc90ee | 648 | # if (SYSLOG_BUFSIZE) >= 256 |
804e6d6d EA |
649 | sbp = sbuf; |
650 | sprintf(sbp, "from=%.200s, size=%ld, class=%d, pri=%ld, nrcpts=%d", | |
733f4837 EA |
651 | e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr, |
652 | e->e_msgsize, e->e_class, e->e_msgpriority, e->e_nrcpts); | |
804e6d6d EA |
653 | sbp += strlen(sbp); |
654 | if (msgid != NULL) | |
655 | { | |
82d343b5 | 656 | sprintf(sbp, ", msgid=%.100s", mbuf); |
07099819 | 657 | sbp += strlen(sbp); |
804e6d6d EA |
658 | } |
659 | if (e->e_bodytype != NULL) | |
660 | { | |
661 | (void) sprintf(sbp, ", bodytype=%.20s", e->e_bodytype); | |
662 | sbp += strlen(sbp); | |
663 | } | |
664 | p = macvalue('r', e); | |
665 | if (p != NULL) | |
666 | (void) sprintf(sbp, ", proto=%.20s", p); | |
667 | syslog(LOG_INFO, "%s: %s, relay=%s", | |
668 | e->e_id, sbuf, name); | |
2bbc90ee EA |
669 | |
670 | # else /* short syslog buffer */ | |
671 | ||
804e6d6d | 672 | syslog(LOG_INFO, "%s: from=%s", |
733f4837 EA |
673 | e->e_id, e->e_from.q_paddr == NULL ? "<NONE>" : |
674 | shortenstring(e->e_from.q_paddr, 83)); | |
804e6d6d EA |
675 | syslog(LOG_INFO, "%s: size=%ld, class=%ld, pri=%ld, nrcpts=%d", |
676 | e->e_id, e->e_msgsize, e->e_class, | |
677 | e->e_msgpriority, e->e_nrcpts); | |
678 | if (msgid != NULL) | |
82d343b5 | 679 | syslog(LOG_INFO, "%s: msgid=%s", e->e_id, mbuf); |
3e05a82f EA |
680 | sbp = sbuf; |
681 | sprintf(sbp, "%s:", e->e_id); | |
682 | sbp += strlen(sbp); | |
804e6d6d | 683 | if (e->e_bodytype != NULL) |
3e05a82f EA |
684 | { |
685 | sprintf(sbp, " bodytype=%s,", e->e_bodytype); | |
686 | sbp += strlen(sbp); | |
687 | } | |
804e6d6d EA |
688 | p = macvalue('r', e); |
689 | if (p != NULL) | |
3e05a82f | 690 | { |
9c086bd3 | 691 | sprintf(sbp, " proto=%s,", p); |
3e05a82f EA |
692 | sbp += strlen(sbp); |
693 | } | |
694 | syslog(LOG_INFO, "%s relay=%s", sbuf, name); | |
2bbc90ee | 695 | # endif |
8b223875 | 696 | # endif |
75a2bcaf EA |
697 | } |
698 | \f/* | |
699 | ** PRIENCODE -- encode external priority names into internal values. | |
700 | ** | |
701 | ** Parameters: | |
702 | ** p -- priority in ascii. | |
703 | ** | |
704 | ** Returns: | |
705 | ** priority as a numeric level. | |
706 | ** | |
707 | ** Side Effects: | |
708 | ** none. | |
709 | */ | |
710 | ||
179d940c | 711 | int |
75a2bcaf EA |
712 | priencode(p) |
713 | char *p; | |
714 | { | |
a444c81b | 715 | register int i; |
75a2bcaf | 716 | |
a444c81b | 717 | for (i = 0; i < NumPriorities; i++) |
75a2bcaf | 718 | { |
ed73ef1d | 719 | if (!strcasecmp(p, Priorities[i].pri_name)) |
a444c81b | 720 | return (Priorities[i].pri_val); |
75a2bcaf | 721 | } |
a444c81b EA |
722 | |
723 | /* unknown priority */ | |
724 | return (0); | |
75a2bcaf EA |
725 | } |
726 | \f/* | |
0908f182 | 727 | ** CRACKADDR -- parse an address and turn it into a macro |
75a2bcaf EA |
728 | ** |
729 | ** This doesn't actually parse the address -- it just extracts | |
730 | ** it and replaces it with "$g". The parse is totally ad hoc | |
731 | ** and isn't even guaranteed to leave something syntactically | |
732 | ** identical to what it started with. However, it does leave | |
733 | ** something semantically identical. | |
734 | ** | |
a7948bd0 EA |
735 | ** This algorithm has been cleaned up to handle a wider range |
736 | ** of cases -- notably quoted and backslash escaped strings. | |
737 | ** This modification makes it substantially better at preserving | |
738 | ** the original syntax. | |
75a2bcaf EA |
739 | ** |
740 | ** Parameters: | |
0908f182 | 741 | ** addr -- the address to be cracked. |
75a2bcaf EA |
742 | ** |
743 | ** Returns: | |
744 | ** a pointer to the new version. | |
745 | ** | |
746 | ** Side Effects: | |
0908f182 | 747 | ** none. |
75a2bcaf EA |
748 | ** |
749 | ** Warning: | |
750 | ** The return value is saved in local storage and should | |
751 | ** be copied if it is to be reused. | |
752 | */ | |
753 | ||
754 | char * | |
0908f182 EA |
755 | crackaddr(addr) |
756 | register char *addr; | |
75a2bcaf EA |
757 | { |
758 | register char *p; | |
a7948bd0 EA |
759 | register char c; |
760 | int cmtlev; | |
97a521ff EA |
761 | int realcmtlev; |
762 | int anglelev, realanglelev; | |
a7948bd0 EA |
763 | int copylev; |
764 | bool qmode; | |
97a521ff EA |
765 | bool realqmode; |
766 | bool skipping; | |
a7948bd0 | 767 | bool putgmac = FALSE; |
27348517 | 768 | bool quoteit = FALSE; |
d4f5b98a | 769 | bool gotangle = FALSE; |
e7a9542d | 770 | bool gotcolon = FALSE; |
75a2bcaf | 771 | register char *bp; |
97a521ff | 772 | char *buflim; |
e7a9542d EA |
773 | char *bufhead; |
774 | char *addrhead; | |
8446c922 | 775 | static char buf[MAXNAME + 1]; |
75a2bcaf | 776 | |
75a2bcaf | 777 | if (tTd(33, 1)) |
0908f182 | 778 | printf("crackaddr(%s)\n", addr); |
75a2bcaf | 779 | |
506fc377 | 780 | /* strip leading spaces */ |
2bee003d | 781 | while (*addr != '\0' && isascii(*addr) && isspace(*addr)) |
506fc377 EA |
782 | addr++; |
783 | ||
75a2bcaf | 784 | /* |
a7948bd0 EA |
785 | ** Start by assuming we have no angle brackets. This will be |
786 | ** adjusted later if we find them. | |
75a2bcaf EA |
787 | */ |
788 | ||
e7a9542d | 789 | bp = bufhead = buf; |
97a521ff | 790 | buflim = &buf[sizeof buf - 5]; |
e7a9542d | 791 | p = addrhead = addr; |
97a521ff EA |
792 | copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0; |
793 | qmode = realqmode = FALSE; | |
a7948bd0 EA |
794 | |
795 | while ((c = *p++) != '\0') | |
75a2bcaf | 796 | { |
97a521ff EA |
797 | /* |
798 | ** If the buffer is overful, go into a special "skipping" | |
799 | ** mode that tries to keep legal syntax but doesn't actually | |
800 | ** output things. | |
801 | */ | |
a7948bd0 | 802 | |
97a521ff | 803 | skipping = bp >= buflim; |
27348517 | 804 | |
97a521ff EA |
805 | if (copylev > 0 && !skipping) |
806 | *bp++ = c; | |
27348517 | 807 | |
a7948bd0 EA |
808 | /* check for backslash escapes */ |
809 | if (c == '\\') | |
75a2bcaf | 810 | { |
07a399c9 EA |
811 | /* arrange to quote the address */ |
812 | if (cmtlev <= 0 && !qmode) | |
813 | quoteit = TRUE; | |
814 | ||
a7948bd0 | 815 | if ((c = *p++) == '\0') |
75a2bcaf | 816 | { |
a7948bd0 EA |
817 | /* too far */ |
818 | p--; | |
819 | goto putg; | |
75a2bcaf | 820 | } |
97a521ff | 821 | if (copylev > 0 && !skipping) |
a7948bd0 EA |
822 | *bp++ = c; |
823 | goto putg; | |
75a2bcaf EA |
824 | } |
825 | ||
a7948bd0 | 826 | /* check for quoted strings */ |
ae5d9ae8 | 827 | if (c == '"' && cmtlev <= 0) |
75a2bcaf | 828 | { |
a7948bd0 | 829 | qmode = !qmode; |
97a521ff EA |
830 | if (copylev > 0 && !skipping) |
831 | realqmode = !realqmode; | |
a7948bd0 | 832 | continue; |
75a2bcaf | 833 | } |
a7948bd0 EA |
834 | if (qmode) |
835 | goto putg; | |
75a2bcaf | 836 | |
a7948bd0 EA |
837 | /* check for comments */ |
838 | if (c == '(') | |
839 | { | |
840 | cmtlev++; | |
97a521ff EA |
841 | |
842 | /* allow space for closing paren */ | |
843 | if (!skipping) | |
844 | { | |
845 | buflim--; | |
846 | realcmtlev++; | |
847 | if (copylev++ <= 0) | |
848 | { | |
849 | *bp++ = ' '; | |
850 | *bp++ = c; | |
851 | } | |
852 | } | |
a7948bd0 EA |
853 | } |
854 | if (cmtlev > 0) | |
75a2bcaf | 855 | { |
a7948bd0 | 856 | if (c == ')') |
75a2bcaf | 857 | { |
a7948bd0 EA |
858 | cmtlev--; |
859 | copylev--; | |
97a521ff EA |
860 | if (!skipping) |
861 | { | |
862 | realcmtlev--; | |
863 | buflim++; | |
864 | } | |
75a2bcaf EA |
865 | } |
866 | continue; | |
867 | } | |
97a521ff EA |
868 | else if (c == ')') |
869 | { | |
870 | /* syntax error: unmatched ) */ | |
3535d73f | 871 | if (copylev > 0 && !skipping) |
97a521ff EA |
872 | bp--; |
873 | } | |
874 | ||
e7a9542d | 875 | /* check for group: list; syntax */ |
6f6c9bdd | 876 | if (c == ':' && anglelev <= 0 && !gotcolon && !ColonOkInAddr) |
e7a9542d EA |
877 | { |
878 | register char *q; | |
879 | ||
6f6c9bdd EA |
880 | if (*p == ':') |
881 | { | |
882 | /* special case -- :: syntax */ | |
883 | if (cmtlev <= 0 && !qmode) | |
884 | quoteit = TRUE; | |
885 | if (copylev > 0 && !skipping) | |
886 | { | |
887 | *bp++ = c; | |
888 | *bp++ = c; | |
889 | } | |
890 | p++; | |
891 | goto putg; | |
892 | } | |
893 | ||
e7a9542d EA |
894 | gotcolon = TRUE; |
895 | ||
e7a9542d | 896 | bp = bufhead; |
6f6c9bdd EA |
897 | if (quoteit) |
898 | { | |
899 | *bp++ = '"'; | |
900 | ||
901 | /* back up over the ':' and any spaces */ | |
902 | --p; | |
903 | while (isascii(*--p) && isspace(*p)) | |
904 | continue; | |
905 | p++; | |
906 | } | |
e7a9542d EA |
907 | for (q = addrhead; q < p; ) |
908 | { | |
909 | c = *q++; | |
910 | if (bp < buflim) | |
911 | { | |
6f6c9bdd EA |
912 | if (quoteit && c == '"') |
913 | *bp++ = '\\'; | |
e7a9542d EA |
914 | *bp++ = c; |
915 | } | |
916 | } | |
6f6c9bdd EA |
917 | if (quoteit) |
918 | { | |
919 | if (bp == &bufhead[1]) | |
920 | bp--; | |
921 | else | |
922 | *bp++ = '"'; | |
923 | while ((c = *p++) != ':') | |
924 | { | |
925 | if (bp < buflim) | |
926 | *bp++ = c; | |
927 | } | |
928 | *bp++ = c; | |
929 | } | |
930 | ||
931 | /* any trailing white space is part of group: */ | |
932 | while (isascii(*p) && isspace(*p) && bp < buflim) | |
933 | *bp++ = *p++; | |
e7a9542d | 934 | copylev = 0; |
6f6c9bdd | 935 | putgmac = quoteit = FALSE; |
e7a9542d EA |
936 | bufhead = bp; |
937 | addrhead = p; | |
938 | continue; | |
939 | } | |
940 | ||
941 | if (c == ';' && copylev <= 0 && !ColonOkInAddr) | |
942 | { | |
e7a9542d EA |
943 | if (bp < buflim) |
944 | *bp++ = c; | |
945 | } | |
946 | ||
97a521ff | 947 | /* check for characters that may have to be quoted */ |
d4f5b98a | 948 | if (strchr(".'@,;:\\()[]", c) != NULL) |
97a521ff EA |
949 | { |
950 | /* | |
951 | ** If these occur as the phrase part of a <> | |
952 | ** construct, but are not inside of () or already | |
953 | ** quoted, they will have to be quoted. Note that | |
954 | ** now (but don't actually do the quoting). | |
955 | */ | |
956 | ||
957 | if (cmtlev <= 0 && !qmode) | |
958 | quoteit = TRUE; | |
959 | } | |
75a2bcaf | 960 | |
a7948bd0 EA |
961 | /* check for angle brackets */ |
962 | if (c == '<') | |
75a2bcaf | 963 | { |
27348517 EA |
964 | register char *q; |
965 | ||
d4f5b98a EA |
966 | /* assume first of two angles is bogus */ |
967 | if (gotangle) | |
968 | quoteit = TRUE; | |
969 | gotangle = TRUE; | |
970 | ||
a7948bd0 | 971 | /* oops -- have to change our mind */ |
ce2496d9 | 972 | anglelev = 1; |
97a521ff | 973 | if (!skipping) |
ce2496d9 | 974 | realanglelev = 1; |
97a521ff | 975 | |
e7a9542d | 976 | bp = bufhead; |
27348517 EA |
977 | if (quoteit) |
978 | { | |
979 | *bp++ = '"'; | |
980 | ||
981 | /* back up over the '<' and any spaces */ | |
982 | --p; | |
2bee003d | 983 | while (isascii(*--p) && isspace(*p)) |
27348517 EA |
984 | continue; |
985 | p++; | |
986 | } | |
e7a9542d | 987 | for (q = addrhead; q < p; ) |
27348517 EA |
988 | { |
989 | c = *q++; | |
97a521ff EA |
990 | if (bp < buflim) |
991 | { | |
992 | if (quoteit && c == '"') | |
993 | *bp++ = '\\'; | |
994 | *bp++ = c; | |
995 | } | |
27348517 EA |
996 | } |
997 | if (quoteit) | |
998 | { | |
d4f5b98a EA |
999 | if (bp == &buf[1]) |
1000 | bp--; | |
1001 | else | |
1002 | *bp++ = '"'; | |
97a521ff EA |
1003 | while ((c = *p++) != '<') |
1004 | { | |
1005 | if (bp < buflim) | |
1006 | *bp++ = c; | |
1007 | } | |
1008 | *bp++ = c; | |
27348517 | 1009 | } |
a7948bd0 | 1010 | copylev = 0; |
27348517 | 1011 | putgmac = quoteit = FALSE; |
a7948bd0 | 1012 | continue; |
75a2bcaf | 1013 | } |
75a2bcaf | 1014 | |
a7948bd0 EA |
1015 | if (c == '>') |
1016 | { | |
97a521ff EA |
1017 | if (anglelev > 0) |
1018 | { | |
1019 | anglelev--; | |
1020 | if (!skipping) | |
1021 | { | |
1022 | realanglelev--; | |
1023 | buflim++; | |
1024 | } | |
1025 | } | |
1026 | else if (!skipping) | |
1027 | { | |
1028 | /* syntax error: unmatched > */ | |
1029 | if (copylev > 0) | |
1030 | bp--; | |
ce2496d9 | 1031 | quoteit = TRUE; |
97a521ff EA |
1032 | continue; |
1033 | } | |
a7948bd0 EA |
1034 | if (copylev++ <= 0) |
1035 | *bp++ = c; | |
1036 | continue; | |
1037 | } | |
75a2bcaf | 1038 | |
a7948bd0 EA |
1039 | /* must be a real address character */ |
1040 | putg: | |
1041 | if (copylev <= 0 && !putgmac) | |
1042 | { | |
2bee003d | 1043 | *bp++ = MACROEXPAND; |
a7948bd0 EA |
1044 | *bp++ = 'g'; |
1045 | putgmac = TRUE; | |
1046 | } | |
75a2bcaf EA |
1047 | } |
1048 | ||
97a521ff EA |
1049 | /* repair any syntactic damage */ |
1050 | if (realqmode) | |
1051 | *bp++ = '"'; | |
1052 | while (realcmtlev-- > 0) | |
1053 | *bp++ = ')'; | |
1054 | while (realanglelev-- > 0) | |
1055 | *bp++ = '>'; | |
a7948bd0 EA |
1056 | *bp++ = '\0'; |
1057 | ||
75a2bcaf | 1058 | if (tTd(33, 1)) |
6c9bd4e1 | 1059 | printf("crackaddr=>`%s'\n", buf); |
75a2bcaf EA |
1060 | |
1061 | return (buf); | |
1062 | } | |
7338e3d4 EA |
1063 | \f/* |
1064 | ** PUTHEADER -- put the header part of a message from the in-core copy | |
1065 | ** | |
1066 | ** Parameters: | |
23fafb99 | 1067 | ** mci -- the connection information. |
c23930c0 | 1068 | ** h -- the header to put. |
7338e3d4 EA |
1069 | ** e -- envelope to use. |
1070 | ** | |
1071 | ** Returns: | |
1072 | ** none. | |
1073 | ** | |
1074 | ** Side Effects: | |
1075 | ** none. | |
1076 | */ | |
1077 | ||
1627a785 EA |
1078 | /* |
1079 | * Macro for fast max (not available in e.g. DG/UX, 386/ix). | |
1080 | */ | |
1081 | #ifndef MAX | |
1082 | # define MAX(a,b) (((a)>(b))?(a):(b)) | |
1083 | #endif | |
1084 | ||
179d940c | 1085 | void |
51d448e5 | 1086 | putheader(mci, h, e) |
23fafb99 | 1087 | register MCI *mci; |
c23930c0 | 1088 | register HDR *h; |
7338e3d4 EA |
1089 | register ENVELOPE *e; |
1090 | { | |
07b49560 | 1091 | char buf[MAX(MAXLINE,BUFSIZ)]; |
07b49560 | 1092 | char obuf[MAXLINE]; |
7338e3d4 | 1093 | |
9f3efbed | 1094 | if (tTd(34, 1)) |
23fafb99 EA |
1095 | printf("--- putheader, mailer = %s ---\n", |
1096 | mci->mci_mailer->m_name); | |
9f3efbed | 1097 | |
c23930c0 EA |
1098 | mci->mci_flags |= MCIF_INHEADER; |
1099 | for (; h != NULL; h = h->h_link) | |
7338e3d4 | 1100 | { |
5161ccf2 | 1101 | register char *p = h->h_value; |
1dbda134 | 1102 | extern bool bitintersect(); |
7338e3d4 | 1103 | |
9f3efbed EA |
1104 | if (tTd(34, 11)) |
1105 | { | |
1106 | printf(" %s: ", h->h_field); | |
5161ccf2 | 1107 | xputs(p); |
9f3efbed EA |
1108 | } |
1109 | ||
d8daa013 EA |
1110 | /* suppress Content-Transfer-Encoding: if we are MIMEing */ |
1111 | if (bitset(H_CTE, h->h_flags) && | |
1112 | bitset(MCIF_CVT8TO7|MCIF_INMIME, mci->mci_flags)) | |
1113 | { | |
1114 | if (tTd(34, 11)) | |
1115 | printf(" (skipped (content-transfer-encoding))\n"); | |
1116 | continue; | |
1117 | } | |
1118 | ||
1119 | if (bitset(MCIF_INMIME, mci->mci_flags)) | |
1120 | goto vanilla; | |
1121 | ||
7338e3d4 | 1122 | if (bitset(H_CHECK|H_ACHECK, h->h_flags) && |
23fafb99 | 1123 | !bitintersect(h->h_mflags, mci->mci_mailer->m_flags)) |
9f3efbed EA |
1124 | { |
1125 | if (tTd(34, 11)) | |
1126 | printf(" (skipped)\n"); | |
7338e3d4 | 1127 | continue; |
9f3efbed | 1128 | } |
7338e3d4 | 1129 | |
a90807d8 EA |
1130 | /* handle Resent-... headers specially */ |
1131 | if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags)) | |
9f3efbed EA |
1132 | { |
1133 | if (tTd(34, 11)) | |
1134 | printf(" (skipped (resent))\n"); | |
a90807d8 | 1135 | continue; |
9f3efbed | 1136 | } |
a90807d8 | 1137 | |
5b4215a7 EA |
1138 | /* suppress return receipts if requested */ |
1139 | if (bitset(H_RECEIPTTO, h->h_flags) && | |
1140 | bitset(EF_NORECEIPT, e->e_flags)) | |
1141 | { | |
1142 | if (tTd(34, 11)) | |
1143 | printf(" (skipped (receipt))\n"); | |
1144 | continue; | |
1145 | } | |
1146 | ||
da9633d1 | 1147 | /* macro expand value if generated internally */ |
7338e3d4 EA |
1148 | if (bitset(H_DEFAULT, h->h_flags)) |
1149 | { | |
832e8a27 | 1150 | expand(p, buf, sizeof buf, e); |
7338e3d4 EA |
1151 | p = buf; |
1152 | if (p == NULL || *p == '\0') | |
da9633d1 EA |
1153 | { |
1154 | if (tTd(34, 11)) | |
1155 | printf(" (skipped -- null value)\n"); | |
7338e3d4 | 1156 | continue; |
da9633d1 | 1157 | } |
7338e3d4 EA |
1158 | } |
1159 | ||
da9633d1 EA |
1160 | if (tTd(34, 11)) |
1161 | printf("\n"); | |
1162 | ||
d2780a78 EA |
1163 | if (bitset(H_STRIPVAL, h->h_flags)) |
1164 | { | |
1165 | /* empty field */ | |
1166 | (void) sprintf(obuf, "%s:", h->h_field); | |
1167 | putline(obuf, mci); | |
1168 | } | |
1169 | else if (bitset(H_FROM|H_RCPT, h->h_flags)) | |
7338e3d4 EA |
1170 | { |
1171 | /* address field */ | |
1172 | bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags); | |
1173 | ||
1174 | if (bitset(H_FROM, h->h_flags)) | |
1175 | oldstyle = FALSE; | |
23fafb99 | 1176 | commaize(h, p, oldstyle, mci, e); |
7338e3d4 EA |
1177 | } |
1178 | else | |
1179 | { | |
1180 | /* vanilla header line */ | |
914bd983 EA |
1181 | register char *nlp; |
1182 | ||
d8daa013 | 1183 | vanilla: |
b6919a63 | 1184 | (void) sprintf(obuf, "%s: ", h->h_field); |
f3d8f6d6 | 1185 | while ((nlp = strchr(p, '\n')) != NULL) |
914bd983 EA |
1186 | { |
1187 | *nlp = '\0'; | |
1188 | (void) strcat(obuf, p); | |
1189 | *nlp = '\n'; | |
23fafb99 | 1190 | putline(obuf, mci); |
914bd983 | 1191 | p = ++nlp; |
56dad217 | 1192 | obuf[0] = '\0'; |
914bd983 EA |
1193 | } |
1194 | (void) strcat(obuf, p); | |
23fafb99 | 1195 | putline(obuf, mci); |
7338e3d4 EA |
1196 | } |
1197 | } | |
7d858063 EA |
1198 | |
1199 | /* | |
1200 | ** If we are converting this to a MIME message, add the | |
28977dbc | 1201 | ** MIME headers. |
7d858063 EA |
1202 | */ |
1203 | ||
8bc4f1c6 | 1204 | #if MIME8TO7 |
7d858063 EA |
1205 | if (bitset(MM_MIME8BIT, MimeMode) && |
1206 | bitset(EF_HAS8BIT, e->e_flags) && | |
a5386d1b | 1207 | !bitset(EF_DONT_MIME, e->e_flags) && |
7d858063 | 1208 | !bitnset(M_8BITS, mci->mci_mailer->m_flags) && |
28977dbc | 1209 | !bitset(MCIF_CVT8TO7, mci->mci_flags)) |
7d858063 | 1210 | { |
28977dbc EA |
1211 | if (hvalue("MIME-Version", e->e_header) == NULL) |
1212 | putline("MIME-Version: 1.0", mci); | |
1213 | if (hvalue("Content-Type", e->e_header) == NULL) | |
1214 | { | |
1215 | sprintf(obuf, "Content-Type: text/plain; charset=%s", | |
3caf3b1f | 1216 | defcharset(e)); |
28977dbc EA |
1217 | putline(obuf, mci); |
1218 | } | |
1219 | if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL) | |
1220 | putline("Content-Transfer-Encoding: 8bit", mci); | |
7d858063 | 1221 | } |
8bc4f1c6 | 1222 | #endif |
7338e3d4 EA |
1223 | } |
1224 | \f/* | |
1225 | ** COMMAIZE -- output a header field, making a comma-translated list. | |
1226 | ** | |
1227 | ** Parameters: | |
1228 | ** h -- the header field to output. | |
1229 | ** p -- the value to put in it. | |
7338e3d4 | 1230 | ** oldstyle -- TRUE if this is an old style header. |
23fafb99 | 1231 | ** mci -- the connection information. |
a4076aed | 1232 | ** e -- the envelope containing the message. |
7338e3d4 EA |
1233 | ** |
1234 | ** Returns: | |
1235 | ** none. | |
1236 | ** | |
1237 | ** Side Effects: | |
1238 | ** outputs "p" to file "fp". | |
1239 | */ | |
1240 | ||
23fafb99 EA |
1241 | void |
1242 | commaize(h, p, oldstyle, mci, e) | |
7338e3d4 EA |
1243 | register HDR *h; |
1244 | register char *p; | |
7338e3d4 | 1245 | bool oldstyle; |
23fafb99 | 1246 | register MCI *mci; |
a4076aed | 1247 | register ENVELOPE *e; |
7338e3d4 EA |
1248 | { |
1249 | register char *obp; | |
1250 | int opos; | |
c4e92f7a | 1251 | int omax; |
7338e3d4 | 1252 | bool firstone = TRUE; |
89dd4c8f | 1253 | char obuf[MAXLINE + 3]; |
7338e3d4 EA |
1254 | |
1255 | /* | |
1256 | ** Output the address list translated by the | |
1257 | ** mailer and with commas. | |
1258 | */ | |
1259 | ||
7338e3d4 EA |
1260 | if (tTd(14, 2)) |
1261 | printf("commaize(%s: %s)\n", h->h_field, p); | |
7338e3d4 | 1262 | |
7338e3d4 | 1263 | obp = obuf; |
b6919a63 | 1264 | (void) sprintf(obp, "%s: ", h->h_field); |
7338e3d4 EA |
1265 | opos = strlen(h->h_field) + 2; |
1266 | obp += opos; | |
e5896557 EA |
1267 | omax = mci->mci_mailer->m_linelimit - 2; |
1268 | if (omax < 0 || omax > 78) | |
1269 | omax = 78; | |
7338e3d4 EA |
1270 | |
1271 | /* | |
1272 | ** Run through the list of values. | |
1273 | */ | |
1274 | ||
1275 | while (*p != '\0') | |
1276 | { | |
1277 | register char *name; | |
85c61679 | 1278 | register int c; |
7338e3d4 | 1279 | char savechar; |
9e43a19e EA |
1280 | int flags; |
1281 | auto int stat; | |
7338e3d4 EA |
1282 | |
1283 | /* | |
1284 | ** Find the end of the name. New style names | |
1285 | ** end with a comma, old style names end with | |
1286 | ** a space character. However, spaces do not | |
1287 | ** necessarily delimit an old-style name -- at | |
1288 | ** signs mean keep going. | |
1289 | */ | |
1290 | ||
1291 | /* find end of name */ | |
2bee003d | 1292 | while ((isascii(*p) && isspace(*p)) || *p == ',') |
7338e3d4 EA |
1293 | p++; |
1294 | name = p; | |
1295 | for (;;) | |
1296 | { | |
9e2cf26f | 1297 | auto char *oldp; |
217a0102 | 1298 | char pvpbuf[PSBUFSIZE]; |
7338e3d4 | 1299 | |
148ea694 | 1300 | (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf, |
800c836f | 1301 | sizeof pvpbuf, &oldp, NULL); |
9e2cf26f | 1302 | p = oldp; |
7338e3d4 EA |
1303 | |
1304 | /* look to see if we have an at sign */ | |
2bee003d | 1305 | while (*p != '\0' && isascii(*p) && isspace(*p)) |
7338e3d4 EA |
1306 | p++; |
1307 | ||
84daea29 | 1308 | if (*p != '@') |
7338e3d4 EA |
1309 | { |
1310 | p = oldp; | |
1311 | break; | |
1312 | } | |
1313 | p += *p == '@' ? 1 : 2; | |
2bee003d | 1314 | while (*p != '\0' && isascii(*p) && isspace(*p)) |
7338e3d4 EA |
1315 | p++; |
1316 | } | |
1317 | /* at the end of one complete name */ | |
1318 | ||
1319 | /* strip off trailing white space */ | |
2bee003d EA |
1320 | while (p >= name && |
1321 | ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0')) | |
7338e3d4 EA |
1322 | p--; |
1323 | if (++p == name) | |
1324 | continue; | |
1325 | savechar = *p; | |
1326 | *p = '\0'; | |
1327 | ||
1328 | /* translate the name to be relative */ | |
9e43a19e EA |
1329 | flags = RF_HEADERADDR|RF_ADDDOMAIN; |
1330 | if (bitset(H_FROM, h->h_flags)) | |
1331 | flags |= RF_SENDERADDR; | |
0159023b | 1332 | #if USERDB |
47fbb920 EA |
1333 | else if (e->e_from.q_mailer != NULL && |
1334 | bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags)) | |
1335 | { | |
1336 | extern char *udbsender(); | |
1337 | ||
1338 | name = udbsender(name); | |
1339 | } | |
1340 | #endif | |
9e43a19e | 1341 | stat = EX_OK; |
23fafb99 | 1342 | name = remotename(name, mci->mci_mailer, flags, &stat, e); |
7338e3d4 EA |
1343 | if (*name == '\0') |
1344 | { | |
1345 | *p = savechar; | |
1346 | continue; | |
1347 | } | |
1348 | ||
1349 | /* output the name with nice formatting */ | |
85c61679 | 1350 | opos += strlen(name); |
7338e3d4 EA |
1351 | if (!firstone) |
1352 | opos += 2; | |
c4e92f7a | 1353 | if (opos > omax && !firstone) |
7338e3d4 | 1354 | { |
db860cb1 | 1355 | (void) strcpy(obp, ",\n"); |
23fafb99 | 1356 | putline(obuf, mci); |
7338e3d4 | 1357 | obp = obuf; |
19decd88 | 1358 | (void) strcpy(obp, " "); |
72a1a2dd EA |
1359 | opos = strlen(obp); |
1360 | obp += opos; | |
85c61679 | 1361 | opos += strlen(name); |
7338e3d4 EA |
1362 | } |
1363 | else if (!firstone) | |
1364 | { | |
19decd88 | 1365 | (void) strcpy(obp, ", "); |
7338e3d4 EA |
1366 | obp += 2; |
1367 | } | |
1368 | ||
85c61679 | 1369 | while ((c = *name++) != '\0' && obp < &obuf[MAXLINE]) |
85c61679 | 1370 | *obp++ = c; |
7338e3d4 EA |
1371 | firstone = FALSE; |
1372 | *p = savechar; | |
1373 | } | |
1374 | (void) strcpy(obp, "\n"); | |
23fafb99 | 1375 | putline(obuf, mci); |
7338e3d4 EA |
1376 | } |
1377 | \f/* | |
84daea29 EA |
1378 | ** COPYHEADER -- copy header list |
1379 | ** | |
1380 | ** This routine is the equivalent of newstr for header lists | |
7338e3d4 EA |
1381 | ** |
1382 | ** Parameters: | |
84daea29 | 1383 | ** header -- list of header structures to copy. |
7338e3d4 EA |
1384 | ** |
1385 | ** Returns: | |
84daea29 | 1386 | ** a copy of 'header'. |
7338e3d4 EA |
1387 | ** |
1388 | ** Side Effects: | |
1389 | ** none. | |
1390 | */ | |
1391 | ||
84daea29 EA |
1392 | HDR * |
1393 | copyheader(header) | |
1394 | register HDR *header; | |
7338e3d4 | 1395 | { |
84daea29 EA |
1396 | register HDR *newhdr; |
1397 | HDR *ret; | |
1398 | register HDR **tail = &ret; | |
7338e3d4 | 1399 | |
84daea29 EA |
1400 | while (header != NULL) |
1401 | { | |
1402 | newhdr = (HDR *) xalloc(sizeof(HDR)); | |
1403 | STRUCTCOPY(*header, *newhdr); | |
1404 | *tail = newhdr; | |
1405 | tail = &newhdr->h_link; | |
1406 | header = header->h_link; | |
1407 | } | |
1408 | *tail = NULL; | |
1409 | ||
1410 | return ret; | |
7338e3d4 | 1411 | } |