Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1437 lines
37 KiB

  1. /*
  2. * Copyright (c) 1983, 1995 Eric P. Allman
  3. * Copyright (c) 1988, 1993
  4. * The Regents of the University of California. All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. All advertising materials mentioning features or use of this software
  15. * must display the following acknowledgement:
  16. * This product includes software developed by the University of
  17. * California, Berkeley and its contributors.
  18. * 4. Neither the name of the University nor the names of its contributors
  19. * may be used to endorse or promote products derived from this software
  20. * without specific prior written permission.
  21. *
  22. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  23. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  24. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  25. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  26. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  27. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  28. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  29. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  31. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  32. * SUCH DAMAGE.
  33. */
  34. #include "smtpinc.h"
  35. #include <listmacr.h>
  36. #include "headers.hxx"
  37. int strcasecmp(char *s1, char *s2);
  38. int strncasecmp(char *s1, char *s2, int n);
  39. struct hdrinfo
  40. {
  41. char *hi_field; /* the name of the field */
  42. unsigned int hi_flags; /* status bits, see below */
  43. };
  44. struct hdrinfo HdrInfo[] =
  45. {
  46. /* originator fields, most to least significant */
  47. "resent-sender", H_FROM|H_RESENT,
  48. "resent-from", H_FROM|H_RESENT,
  49. "resent-reply-to", H_FROM|H_RESENT,
  50. "sender", H_FROM,
  51. "from", H_FROM,
  52. "reply-to", H_FROM,
  53. "full-name", 0,
  54. "return-receipt-to", H_FROM|H_RECEIPTTO,
  55. "errors-to", H_FROM|H_ERRORSTO,
  56. /* destination fields */
  57. "to", H_RCPT,
  58. "resent-to", H_RCPT|H_RESENT,
  59. "cc", H_RCPT,
  60. "resent-cc", H_RCPT|H_RESENT,
  61. "bcc", H_RCPT,
  62. "resent-bcc", H_RCPT|H_RESENT,
  63. "apparently-to", H_RCPT,
  64. /* message identification and control */
  65. "message-id", H_MID,
  66. "resent-message-id", H_RESENT,
  67. /* date fields */
  68. "date", H_DATE,
  69. "resent-date", H_RESENT,
  70. /* trace fields */
  71. "received", 0,
  72. "x400-received", 0,
  73. "via", 0,
  74. "mail-from", H_TRACE,
  75. /* miscellaneous fields */
  76. "comments", 0,
  77. "return-path", H_RETURNPATH,
  78. "subject", H_SUBJECT,
  79. /* X-Headers */
  80. "x-sender", H_X_SENDER,
  81. "x-receiver", H_X_RECEIVER,
  82. // 10/15/98 - MikeSwa Added supersedes headers
  83. "x-msgguid", H_X_MSGGUID,
  84. "x-supersedesmsgguid",H_X_SUPERSEDES_MSGGUID,
  85. // 12/18/98 -- pgopi. Added X-originalArrivalTime header
  86. "x-originalarrivaltime" , H_X_ORIGINAL_ARRIVAL_TIME,
  87. NULL, 0,
  88. };
  89. #define xalloc(size) HeapAlloc(GetProcessHeap(), 0, size)
  90. /*
  91. ** CHOMPHEADER -- process and save a header line.
  92. **
  93. ** Called by collect and by readcf to deal with header lines.
  94. **
  95. ** Parameters:
  96. ** line -- header as a text line.
  97. ** def -- if set, this is a default value.
  98. ** hdrp -- a pointer to the place to save the header.
  99. ** e -- the envelope including this header.
  100. **
  101. ** Returns:
  102. ** flags for this header.
  103. **
  104. ** Side Effects:
  105. ** The header is saved on the header list.
  106. ** Contents of 'line' are destroyed.
  107. */
  108. BOOL ChompHeader(char * line, DWORD& HeaderFlags, char ** ppszValueBuf)
  109. {
  110. register char *p = line;
  111. HEADERVAL *h = NULL;
  112. char *fname = NULL;
  113. char *fvalue = NULL;
  114. char *oldfvalue = NULL;
  115. struct hdrinfo *hi = NULL;
  116. DWORD fNameSize;
  117. /* find canonical name */
  118. fname = p;
  119. while (isascii(*p) && isgraph(*p) && *p != ':')
  120. p++;
  121. fvalue = p;
  122. while (isascii(*p) && isspace(*p))
  123. p++;
  124. //See if we had anything atall
  125. if(p == line)
  126. {
  127. //We had a seperator CRLF
  128. HeaderFlags |= H_EOH;
  129. return (FALSE);
  130. }
  131. if (*p++ != ':' || fname == fvalue)
  132. {
  133. //syserr("553 header syntax error, line \"%s\"", line);
  134. return (FALSE);
  135. }
  136. fvalue = p;
  137. if(ppszValueBuf)
  138. *ppszValueBuf = fvalue;
  139. fNameSize = (DWORD)((p - line) - 1);
  140. /* see if it is a known type */
  141. for (hi = HdrInfo; hi->hi_field != NULL; hi++)
  142. {
  143. if (strncasecmp(hi->hi_field, fname, fNameSize) == 0)
  144. {
  145. HeaderFlags |= hi->hi_flags; //set our flag
  146. break;
  147. }
  148. }
  149. return (TRUE);
  150. }
  151. #if 0
  152. /*
  153. ** ADDHEADER -- add a header entry to the end of the queue.
  154. **
  155. ** This bypasses the special checking of chompheader.
  156. **
  157. ** Parameters:
  158. ** field -- the name of the header field.
  159. ** value -- the value of the field.
  160. ** hp -- an indirect pointer to the header structure list.
  161. **
  162. ** Returns:
  163. ** none.
  164. **
  165. ** Side Effects:
  166. ** adds the field on the list of headers for this envelope.
  167. */
  168. void
  169. addheader(field, value, hdrlist)
  170. char *field;
  171. char *value;
  172. HDR **hdrlist;
  173. {
  174. register HDR *h;
  175. register struct hdrinfo *hi;
  176. HDR **hp;
  177. /* find info struct */
  178. for (hi = HdrInfo; hi->hi_field != NULL; hi++)
  179. {
  180. if (strcasecmp(field, hi->hi_field) == 0)
  181. break;
  182. }
  183. /* find current place in list -- keep back pointer? */
  184. for (hp = hdrlist; (h = *hp) != NULL; hp = &h->h_link)
  185. {
  186. if (strcasecmp(field, h->h_field) == 0)
  187. break;
  188. }
  189. /* allocate space for new header */
  190. h = (HDR *) xalloc(sizeof *h);
  191. h->h_field = field;
  192. h->h_value = newstr(value);
  193. h->h_link = *hp;
  194. h->h_flags = hi->hi_flags | H_DEFAULT;
  195. clrbitmap(h->h_mflags);
  196. *hp = h;
  197. }
  198. /*
  199. ** HVALUE -- return value of a header.
  200. **
  201. ** Only "real" fields (i.e., ones that have not been supplied
  202. ** as a default) are used.
  203. **
  204. ** Parameters:
  205. ** field -- the field name.
  206. ** header -- the header list.
  207. **
  208. ** Returns:
  209. ** pointer to the value part.
  210. ** NULL if not found.
  211. **
  212. ** Side Effects:
  213. ** none.
  214. */
  215. char * hvalue(char * field, HDR * header)
  216. {
  217. register HDR *h;
  218. for (h = header; h != NULL; h = h->h_link)
  219. {
  220. if (!bitset(H_DEFAULT, h->h_flags) &&
  221. strcasecmp(h->h_field, field) == 0)
  222. return (h->h_value);
  223. }
  224. return (NULL);
  225. }
  226. #endif
  227. /*
  228. ** ISHEADER -- predicate telling if argument is a header.
  229. **
  230. ** A line is a header if it has a single word followed by
  231. ** optional white space followed by a colon.
  232. **
  233. ** Header fields beginning with two dashes, although technically
  234. ** permitted by RFC822, are automatically rejected in order
  235. ** to make MIME work out. Without this we could have a technically
  236. ** legal header such as ``--"foo:bar"'' that would also be a legal
  237. ** MIME separator.
  238. **
  239. ** Parameters:
  240. ** h -- string to check for possible headerness.
  241. **
  242. ** Returns:
  243. ** TRUE if h is a header.
  244. ** FALSE otherwise.
  245. **
  246. ** Side Effects:
  247. ** none.
  248. */
  249. BOOL IsHeader(char *h)
  250. {
  251. register char *s = h;
  252. if (s[0] == '-' && s[1] == '-')
  253. return FALSE;
  254. while (*s > ' ' && *s != ':' && *s != '\0')
  255. s++;
  256. if (h == s)
  257. return FALSE;
  258. /* following technically violates RFC822 */
  259. while (isascii(*s) && isspace(*s))
  260. s++;
  261. return (*s == ':');
  262. }
  263. #if 0
  264. /*
  265. ** EATHEADER -- run through the stored header and extract info.
  266. **
  267. ** Parameters:
  268. ** e -- the envelope to process.
  269. ** full -- if set, do full processing (e.g., compute
  270. ** message priority). This should not be set
  271. ** when reading a queue file because some info
  272. ** needed to compute the priority is wrong.
  273. **
  274. ** Returns:
  275. ** none.
  276. **
  277. ** Side Effects:
  278. ** Sets a bunch of global variables from information
  279. ** in the collected header.
  280. ** Aborts the message if the hop count is exceeded.
  281. */
  282. void
  283. eatheader(e, full)
  284. register ENVELOPE *e;
  285. bool full;
  286. {
  287. register HDR *h;
  288. register char *p;
  289. int hopcnt = 0;
  290. char *msgid;
  291. char buf[MAXLINE];
  292. /*
  293. ** Set up macros for possible expansion in headers.
  294. */
  295. define('f', e->e_sender, e);
  296. define('g', e->e_sender, e);
  297. if (e->e_origrcpt != NULL && *e->e_origrcpt != '\0')
  298. define('u', e->e_origrcpt, e);
  299. else
  300. define('u', NULL, e);
  301. /* full name of from person */
  302. p = hvalue("full-name", e->e_header);
  303. if (p != NULL)
  304. define('x', p, e);
  305. if (tTd(32, 1))
  306. printf("----- collected header -----\n");
  307. msgid = NULL;
  308. for (h = e->e_header; h != NULL; h = h->h_link)
  309. {
  310. if (tTd(32, 1))
  311. printf("%s: ", h->h_field);
  312. if (h->h_value == NULL)
  313. {
  314. if (tTd(32, 1))
  315. printf("<NULL>\n");
  316. continue;
  317. }
  318. /* do early binding */
  319. if (bitset(H_DEFAULT, h->h_flags))
  320. {
  321. if (tTd(32, 1))
  322. {
  323. printf("(");
  324. xputs(h->h_value);
  325. printf(") ");
  326. }
  327. expand(h->h_value, buf, sizeof buf, e);
  328. if (buf[0] != '\0')
  329. {
  330. if (bitset(H_FROM, h->h_flags))
  331. {
  332. extern char *crackaddr();
  333. expand(crackaddr(buf), buf, sizeof buf, e);
  334. }
  335. h->h_value = newstr(buf);
  336. h->h_flags &= ~H_DEFAULT;
  337. }
  338. }
  339. if (tTd(32, 1))
  340. {
  341. xputs(h->h_value);
  342. printf("\n");
  343. }
  344. /* count the number of times it has been processed */
  345. if (bitset(H_TRACE, h->h_flags))
  346. hopcnt++;
  347. /* send to this person if we so desire */
  348. if (GrabTo && bitset(H_RCPT, h->h_flags) &&
  349. !bitset(H_DEFAULT, h->h_flags) &&
  350. (!bitset(EF_RESENT, e->e_flags) || bitset(H_RESENT, h->h_flags)))
  351. {
  352. int saveflags = e->e_flags;
  353. (void) sendtolist(h->h_value, NULLADDR,
  354. &e->e_sendqueue, 0, e);
  355. /* delete fatal errors generated by this address */
  356. if (!GrabTo && !bitset(EF_FATALERRS, saveflags))
  357. e->e_flags &= ~EF_FATALERRS;
  358. }
  359. /* save the message-id for logging */
  360. p = "resent-message-id";
  361. if (!bitset(EF_RESENT, e->e_flags))
  362. p += 7;
  363. if (strcasecmp(h->h_field, p) == 0)
  364. {
  365. msgid = h->h_value;
  366. while (isascii(*msgid) && isspace(*msgid))
  367. msgid++;
  368. }
  369. /* see if this is a return-receipt header */
  370. if (bitset(H_RECEIPTTO, h->h_flags))
  371. e->e_receiptto = h->h_value;
  372. }
  373. if (tTd(32, 1))
  374. printf("----------------------------\n");
  375. /* if we are just verifying (that is, sendmail -t -bv), drop out now */
  376. if (OpMode == MD_VERIFY)
  377. return;
  378. /* store hop count */
  379. if (hopcnt > e->e_hopcount)
  380. e->e_hopcount = hopcnt;
  381. /* message priority */
  382. p = hvalue("precedence", e->e_header);
  383. if (p != NULL)
  384. e->e_class = priencode(p);
  385. if (e->e_class < 0)
  386. e->e_timeoutclass = TOC_NONURGENT;
  387. else if (e->e_class > 0)
  388. e->e_timeoutclass = TOC_URGENT;
  389. if (full)
  390. {
  391. e->e_msgpriority = e->e_msgsize
  392. - e->e_class * WkClassFact
  393. + e->e_nrcpts * WkRecipFact;
  394. }
  395. /* message timeout priority */
  396. p = hvalue("priority", e->e_header);
  397. if (p != NULL)
  398. {
  399. /* (this should be in the configuration file) */
  400. if (strcasecmp(p, "urgent"))
  401. e->e_timeoutclass = TOC_URGENT;
  402. else if (strcasecmp(p, "normal"))
  403. e->e_timeoutclass = TOC_NORMAL;
  404. else if (strcasecmp(p, "non-urgent"))
  405. e->e_timeoutclass = TOC_NONURGENT;
  406. }
  407. /* date message originated */
  408. p = hvalue("posted-date", e->e_header);
  409. if (p == NULL)
  410. p = hvalue("date", e->e_header);
  411. if (p != NULL)
  412. define('a', p, e);
  413. /* check to see if this is a MIME message */
  414. if ((e->e_bodytype != NULL &&
  415. strcasecmp(e->e_bodytype, "8BITMIME") == 0) ||
  416. hvalue("MIME-Version", e->e_header) != NULL)
  417. {
  418. e->e_flags |= EF_IS_MIME;
  419. if (HasEightBits)
  420. e->e_bodytype = "8BITMIME";
  421. }
  422. else if ((p = hvalue("Content-Type", e->e_header)) != NULL)
  423. {
  424. /* this may be an RFC 1049 message */
  425. p = strpbrk(p, ";/");
  426. if (p == NULL || *p == ';')
  427. {
  428. /* yep, it is */
  429. e->e_flags |= EF_DONT_MIME;
  430. }
  431. }
  432. /*
  433. ** From person in antiquated ARPANET mode
  434. ** required by UK Grey Book e-mail gateways (sigh)
  435. */
  436. if (OpMode == MD_ARPAFTP)
  437. {
  438. register struct hdrinfo *hi;
  439. for (hi = HdrInfo; hi->hi_field != NULL; hi++)
  440. {
  441. if (bitset(H_FROM, hi->hi_flags) &&
  442. (!bitset(H_RESENT, hi->hi_flags) ||
  443. bitset(EF_RESENT, e->e_flags)) &&
  444. (p = hvalue(hi->hi_field, e->e_header)) != NULL)
  445. break;
  446. }
  447. if (hi->hi_field != NULL)
  448. {
  449. if (tTd(32, 2))
  450. printf("eatheader: setsender(*%s == %s)\n",
  451. hi->hi_field, p);
  452. setsender(p, e, NULL, TRUE);
  453. }
  454. }
  455. /*
  456. ** Log collection information.
  457. */
  458. # ifdef LOG
  459. if (bitset(EF_LOGSENDER, e->e_flags) && LogLevel > 4)
  460. logsender(e, msgid);
  461. # endif /* LOG */
  462. e->e_flags &= ~EF_LOGSENDER;
  463. }
  464. /*
  465. ** LOGSENDER -- log sender information
  466. **
  467. ** Parameters:
  468. ** e -- the envelope to log
  469. ** msgid -- the message id
  470. **
  471. ** Returns:
  472. ** none
  473. */
  474. void
  475. logsender(e, msgid)
  476. register ENVELOPE *e;
  477. char *msgid;
  478. {
  479. # ifdef LOG
  480. char *name;
  481. register char *sbp;
  482. register char *p;
  483. int l;
  484. char hbuf[MAXNAME + 1];
  485. char sbuf[MAXLINE + 1];
  486. char mbuf[MAXNAME + 1];
  487. /* don't allow newlines in the message-id */
  488. if (msgid != NULL)
  489. {
  490. l = strlen(msgid);
  491. if (l > sizeof mbuf - 1)
  492. l = sizeof mbuf - 1;
  493. bcopy(msgid, mbuf, l);
  494. mbuf[l] = '\0';
  495. p = mbuf;
  496. while ((p = strchr(p, '\n')) != NULL)
  497. *p++ = ' ';
  498. }
  499. if (bitset(EF_RESPONSE, e->e_flags))
  500. name = "[RESPONSE]";
  501. else if ((name = macvalue('_', e)) != NULL)
  502. ;
  503. else if (RealHostName == NULL)
  504. name = "localhost";
  505. else if (RealHostName[0] == '[')
  506. name = RealHostName;
  507. else
  508. {
  509. name = hbuf;
  510. (void) sprintf(hbuf, "%.80s", RealHostName);
  511. if (RealHostAddr.sa.sa_family != 0)
  512. {
  513. p = &hbuf[strlen(hbuf)];
  514. (void) sprintf(p, " (%s)",
  515. anynet_ntoa(&RealHostAddr));
  516. }
  517. }
  518. /* some versions of syslog only take 5 printf args */
  519. # if (SYSLOG_BUFSIZE) >= 256
  520. sbp = sbuf;
  521. sprintf(sbp, "from=%.200s, size=%ld, class=%d, pri=%ld, nrcpts=%d",
  522. e->e_from.q_paddr == NULL ? "<NONE>" : e->e_from.q_paddr,
  523. e->e_msgsize, e->e_class, e->e_msgpriority, e->e_nrcpts);
  524. sbp += strlen(sbp);
  525. if (msgid != NULL)
  526. {
  527. sprintf(sbp, ", msgid=%.100s", mbuf);
  528. sbp += strlen(sbp);
  529. }
  530. if (e->e_bodytype != NULL)
  531. {
  532. (void) sprintf(sbp, ", bodytype=%.20s", e->e_bodytype);
  533. sbp += strlen(sbp);
  534. }
  535. p = macvalue('r', e);
  536. if (p != NULL)
  537. (void) sprintf(sbp, ", proto=%.20s", p);
  538. syslog(LOG_INFO, "%s: %s, relay=%s",
  539. e->e_id, sbuf, name);
  540. # else /* short syslog buffer */
  541. syslog(LOG_INFO, "%s: from=%s",
  542. e->e_id, e->e_from.q_paddr == NULL ? "<NONE>" :
  543. shortenstring(e->e_from.q_paddr, 83));
  544. syslog(LOG_INFO, "%s: size=%ld, class=%ld, pri=%ld, nrcpts=%d",
  545. e->e_id, e->e_msgsize, e->e_class,
  546. e->e_msgpriority, e->e_nrcpts);
  547. if (msgid != NULL)
  548. syslog(LOG_INFO, "%s: msgid=%s", e->e_id, mbuf);
  549. sbp = sbuf;
  550. sprintf(sbp, "%s:", e->e_id);
  551. sbp += strlen(sbp);
  552. if (e->e_bodytype != NULL)
  553. {
  554. sprintf(sbp, " bodytype=%s,", e->e_bodytype);
  555. sbp += strlen(sbp);
  556. }
  557. p = macvalue('r', e);
  558. if (p != NULL)
  559. {
  560. sprintf(sbp, " proto=%s,", p);
  561. sbp += strlen(sbp);
  562. }
  563. syslog(LOG_INFO, "%s relay=%s", sbuf, name);
  564. # endif
  565. # endif
  566. }
  567. /*
  568. ** PRIENCODE -- encode external priority names into internal values.
  569. **
  570. ** Parameters:
  571. ** p -- priority in ascii.
  572. **
  573. ** Returns:
  574. ** priority as a numeric level.
  575. **
  576. ** Side Effects:
  577. ** none.
  578. */
  579. int
  580. priencode(p)
  581. char *p;
  582. {
  583. register int i;
  584. for (i = 0; i < NumPriorities; i++)
  585. {
  586. if (!strcasecmp(p, Priorities[i].pri_name))
  587. return (Priorities[i].pri_val);
  588. }
  589. /* unknown priority */
  590. return (0);
  591. }
  592. /*
  593. ** CRACKADDR -- parse an address and turn it into a macro
  594. **
  595. ** This doesn't actually parse the address -- it just extracts
  596. ** it and replaces it with "$g". The parse is totally ad hoc
  597. ** and isn't even guaranteed to leave something syntactically
  598. ** identical to what it started with. However, it does leave
  599. ** something semantically identical.
  600. **
  601. ** This algorithm has been cleaned up to handle a wider range
  602. ** of cases -- notably quoted and backslash escaped strings.
  603. ** This modification makes it substantially better at preserving
  604. ** the original syntax.
  605. **
  606. ** Parameters:
  607. ** addr -- the address to be cracked.
  608. **
  609. ** Returns:
  610. ** a pointer to the new version.
  611. **
  612. ** Side Effects:
  613. ** none.
  614. **
  615. ** Warning:
  616. ** The return value is saved in local storage and should
  617. ** be copied if it is to be reused.
  618. */
  619. char *
  620. crackaddr(addr)
  621. register char *addr;
  622. {
  623. register char *p;
  624. register char c;
  625. int cmtlev;
  626. int realcmtlev;
  627. int anglelev, realanglelev;
  628. int copylev;
  629. bool qmode;
  630. bool realqmode;
  631. bool skipping;
  632. bool putgmac = FALSE;
  633. bool quoteit = FALSE;
  634. bool gotangle = FALSE;
  635. bool gotcolon = FALSE;
  636. register char *bp;
  637. char *buflim;
  638. char *bufhead;
  639. char *addrhead;
  640. static char buf[MAXNAME + 1];
  641. if (tTd(33, 1))
  642. printf("crackaddr(%s)\n", addr);
  643. /* strip leading spaces */
  644. while (*addr != '\0' && isascii(*addr) && isspace(*addr))
  645. addr++;
  646. /*
  647. ** Start by assuming we have no angle brackets. This will be
  648. ** adjusted later if we find them.
  649. */
  650. bp = bufhead = buf;
  651. buflim = &buf[sizeof buf - 5];
  652. p = addrhead = addr;
  653. copylev = anglelev = realanglelev = cmtlev = realcmtlev = 0;
  654. qmode = realqmode = FALSE;
  655. while ((c = *p++) != '\0')
  656. {
  657. /*
  658. ** If the buffer is overful, go into a special "skipping"
  659. ** mode that tries to keep legal syntax but doesn't actually
  660. ** output things.
  661. */
  662. skipping = bp >= buflim;
  663. if (copylev > 0 && !skipping)
  664. *bp++ = c;
  665. /* check for backslash escapes */
  666. if (c == '\\')
  667. {
  668. /* arrange to quote the address */
  669. if (cmtlev <= 0 && !qmode)
  670. quoteit = TRUE;
  671. if ((c = *p++) == '\0')
  672. {
  673. /* too far */
  674. p--;
  675. goto putg;
  676. }
  677. if (copylev > 0 && !skipping)
  678. *bp++ = c;
  679. goto putg;
  680. }
  681. /* check for quoted strings */
  682. if (c == '"' && cmtlev <= 0)
  683. {
  684. qmode = !qmode;
  685. if (copylev > 0 && !skipping)
  686. realqmode = !realqmode;
  687. continue;
  688. }
  689. if (qmode)
  690. goto putg;
  691. /* check for comments */
  692. if (c == '(')
  693. {
  694. cmtlev++;
  695. /* allow space for closing paren */
  696. if (!skipping)
  697. {
  698. buflim--;
  699. realcmtlev++;
  700. if (copylev++ <= 0)
  701. {
  702. *bp++ = ' ';
  703. *bp++ = c;
  704. }
  705. }
  706. }
  707. if (cmtlev > 0)
  708. {
  709. if (c == ')')
  710. {
  711. cmtlev--;
  712. copylev--;
  713. if (!skipping)
  714. {
  715. realcmtlev--;
  716. buflim++;
  717. }
  718. }
  719. continue;
  720. }
  721. else if (c == ')')
  722. {
  723. /* syntax error: unmatched ) */
  724. if (copylev > 0 && !skipping)
  725. bp--;
  726. }
  727. /* check for group: list; syntax */
  728. if (c == ':' && anglelev <= 0 && !gotcolon && !ColonOkInAddr)
  729. {
  730. register char *q;
  731. if (*p == ':')
  732. {
  733. /* special case -- :: syntax */
  734. if (cmtlev <= 0 && !qmode)
  735. quoteit = TRUE;
  736. if (copylev > 0 && !skipping)
  737. {
  738. *bp++ = c;
  739. *bp++ = c;
  740. }
  741. p++;
  742. goto putg;
  743. }
  744. gotcolon = TRUE;
  745. bp = bufhead;
  746. if (quoteit)
  747. {
  748. *bp++ = '"';
  749. /* back up over the ':' and any spaces */
  750. --p;
  751. while (isascii(*--p) && isspace(*p))
  752. continue;
  753. p++;
  754. }
  755. for (q = addrhead; q < p; )
  756. {
  757. c = *q++;
  758. if (bp < buflim)
  759. {
  760. if (quoteit && c == '"')
  761. *bp++ = '\\';
  762. *bp++ = c;
  763. }
  764. }
  765. if (quoteit)
  766. {
  767. if (bp == &bufhead[1])
  768. bp--;
  769. else
  770. *bp++ = '"';
  771. while ((c = *p++) != ':')
  772. {
  773. if (bp < buflim)
  774. *bp++ = c;
  775. }
  776. *bp++ = c;
  777. }
  778. /* any trailing white space is part of group: */
  779. while (isascii(*p) && isspace(*p) && bp < buflim)
  780. *bp++ = *p++;
  781. copylev = 0;
  782. putgmac = quoteit = FALSE;
  783. bufhead = bp;
  784. addrhead = p;
  785. continue;
  786. }
  787. if (c == ';' && copylev <= 0 && !ColonOkInAddr)
  788. {
  789. if (bp < buflim)
  790. *bp++ = c;
  791. }
  792. /* check for characters that may have to be quoted */
  793. if (strchr(MustQuoteChars, c) != NULL)
  794. {
  795. /*
  796. ** If these occur as the phrase part of a <>
  797. ** construct, but are not inside of () or already
  798. ** quoted, they will have to be quoted. Note that
  799. ** now (but don't actually do the quoting).
  800. */
  801. if (cmtlev <= 0 && !qmode)
  802. quoteit = TRUE;
  803. }
  804. /* check for angle brackets */
  805. if (c == '<')
  806. {
  807. register char *q;
  808. /* assume first of two angles is bogus */
  809. if (gotangle)
  810. quoteit = TRUE;
  811. gotangle = TRUE;
  812. /* oops -- have to change our mind */
  813. anglelev = 1;
  814. if (!skipping)
  815. realanglelev = 1;
  816. bp = bufhead;
  817. if (quoteit)
  818. {
  819. *bp++ = '"';
  820. /* back up over the '<' and any spaces */
  821. --p;
  822. while (isascii(*--p) && isspace(*p))
  823. continue;
  824. p++;
  825. }
  826. for (q = addrhead; q < p; )
  827. {
  828. c = *q++;
  829. if (bp < buflim)
  830. {
  831. if (quoteit && c == '"')
  832. *bp++ = '\\';
  833. *bp++ = c;
  834. }
  835. }
  836. if (quoteit)
  837. {
  838. if (bp == &buf[1])
  839. bp--;
  840. else
  841. *bp++ = '"';
  842. while ((c = *p++) != '<')
  843. {
  844. if (bp < buflim)
  845. *bp++ = c;
  846. }
  847. *bp++ = c;
  848. }
  849. copylev = 0;
  850. putgmac = quoteit = FALSE;
  851. continue;
  852. }
  853. if (c == '>')
  854. {
  855. if (anglelev > 0)
  856. {
  857. anglelev--;
  858. if (!skipping)
  859. {
  860. realanglelev--;
  861. buflim++;
  862. }
  863. }
  864. else if (!skipping)
  865. {
  866. /* syntax error: unmatched > */
  867. if (copylev > 0)
  868. bp--;
  869. quoteit = TRUE;
  870. continue;
  871. }
  872. if (copylev++ <= 0)
  873. *bp++ = c;
  874. continue;
  875. }
  876. /* must be a real address character */
  877. putg:
  878. if (copylev <= 0 && !putgmac)
  879. {
  880. *bp++ = MACROEXPAND;
  881. *bp++ = 'g';
  882. putgmac = TRUE;
  883. }
  884. }
  885. /* repair any syntactic damage */
  886. if (realqmode)
  887. *bp++ = '"';
  888. while (realcmtlev-- > 0)
  889. *bp++ = ')';
  890. while (realanglelev-- > 0)
  891. *bp++ = '>';
  892. *bp++ = '\0';
  893. if (tTd(33, 1))
  894. printf("crackaddr=>`%s'\n", buf);
  895. return (buf);
  896. }
  897. /*
  898. ** PUTHEADER -- put the header part of a message from the in-core copy
  899. **
  900. ** Parameters:
  901. ** mci -- the connection information.
  902. ** h -- the header to put.
  903. ** e -- envelope to use.
  904. **
  905. ** Returns:
  906. ** none.
  907. **
  908. ** Side Effects:
  909. ** none.
  910. */
  911. /*
  912. * Macro for fast max (not available in e.g. DG/UX, 386/ix).
  913. */
  914. #ifndef MAX
  915. # define MAX(a,b) (((a)>(b))?(a):(b))
  916. #endif
  917. void
  918. putheader(mci, h, e)
  919. register MCI *mci;
  920. register HDR *h;
  921. register ENVELOPE *e;
  922. {
  923. char buf[MAX(MAXLINE,BUFSIZ)];
  924. char obuf[MAXLINE];
  925. if (tTd(34, 1))
  926. printf("--- putheader, mailer = %s ---\n",
  927. mci->mci_mailer->m_name);
  928. mci->mci_flags |= MCIF_INHEADER;
  929. for (; h != NULL; h = h->h_link)
  930. {
  931. register char *p = h->h_value;
  932. extern bool bitintersect();
  933. if (tTd(34, 11))
  934. {
  935. printf(" %s: ", h->h_field);
  936. xputs(p);
  937. }
  938. /* suppress Content-Transfer-Encoding: if we are MIMEing */
  939. if (bitset(H_CTE, h->h_flags) &&
  940. bitset(MCIF_CVT8TO7|MCIF_INMIME, mci->mci_flags))
  941. {
  942. if (tTd(34, 11))
  943. printf(" (skipped (content-transfer-encoding))\n");
  944. continue;
  945. }
  946. if (bitset(MCIF_INMIME, mci->mci_flags))
  947. goto vanilla;
  948. if (bitset(H_CHECK|H_ACHECK, h->h_flags) &&
  949. !bitintersect(h->h_mflags, mci->mci_mailer->m_flags))
  950. {
  951. if (tTd(34, 11))
  952. printf(" (skipped)\n");
  953. continue;
  954. }
  955. /* handle Resent-... headers specially */
  956. if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
  957. {
  958. if (tTd(34, 11))
  959. printf(" (skipped (resent))\n");
  960. continue;
  961. }
  962. /* suppress return receipts if requested */
  963. if (bitset(H_RECEIPTTO, h->h_flags) &&
  964. bitset(EF_NORECEIPT, e->e_flags))
  965. {
  966. if (tTd(34, 11))
  967. printf(" (skipped (receipt))\n");
  968. continue;
  969. }
  970. /* macro expand value if generated internally */
  971. if (bitset(H_DEFAULT, h->h_flags))
  972. {
  973. expand(p, buf, sizeof buf, e);
  974. p = buf;
  975. if (p == NULL || *p == '\0')
  976. {
  977. if (tTd(34, 11))
  978. printf(" (skipped -- null value)\n");
  979. continue;
  980. }
  981. }
  982. if (tTd(34, 11))
  983. printf("\n");
  984. if (bitset(H_STRIPVAL, h->h_flags))
  985. {
  986. /* empty field */
  987. (void) sprintf(obuf, "%s:", h->h_field);
  988. putline(obuf, mci);
  989. }
  990. else if (bitset(H_FROM|H_RCPT, h->h_flags))
  991. {
  992. /* address field */
  993. bool oldstyle = bitset(EF_OLDSTYLE, e->e_flags);
  994. if (bitset(H_FROM, h->h_flags))
  995. oldstyle = FALSE;
  996. commaize(h, p, oldstyle, mci, e);
  997. }
  998. else
  999. {
  1000. /* vanilla header line */
  1001. register char *nlp;
  1002. vanilla:
  1003. (void) sprintf(obuf, "%s: ", h->h_field);
  1004. while ((nlp = strchr(p, '\n')) != NULL)
  1005. {
  1006. *nlp = '\0';
  1007. (void) strcat(obuf, p);
  1008. *nlp = '\n';
  1009. putline(obuf, mci);
  1010. p = ++nlp;
  1011. obuf[0] = '\0';
  1012. }
  1013. (void) strcat(obuf, p);
  1014. putline(obuf, mci);
  1015. }
  1016. }
  1017. /*
  1018. ** If we are converting this to a MIME message, add the
  1019. ** MIME headers.
  1020. */
  1021. #if MIME8TO7
  1022. if (bitset(MM_MIME8BIT, MimeMode) &&
  1023. bitset(EF_HAS8BIT, e->e_flags) &&
  1024. !bitset(EF_DONT_MIME, e->e_flags) &&
  1025. !bitnset(M_8BITS, mci->mci_mailer->m_flags) &&
  1026. !bitset(MCIF_CVT8TO7, mci->mci_flags))
  1027. {
  1028. if (hvalue("MIME-Version", e->e_header) == NULL)
  1029. putline("MIME-Version: 1.0", mci);
  1030. if (hvalue("Content-Type", e->e_header) == NULL)
  1031. {
  1032. sprintf(obuf, "Content-Type: text/plain; charset=%s",
  1033. defcharset(e));
  1034. putline(obuf, mci);
  1035. }
  1036. if (hvalue("Content-Transfer-Encoding", e->e_header) == NULL)
  1037. putline("Content-Transfer-Encoding: 8bit", mci);
  1038. }
  1039. #endif
  1040. }
  1041. /*
  1042. ** COMMAIZE -- output a header field, making a comma-translated list.
  1043. **
  1044. ** Parameters:
  1045. ** h -- the header field to output.
  1046. ** p -- the value to put in it.
  1047. ** oldstyle -- TRUE if this is an old style header.
  1048. ** mci -- the connection information.
  1049. ** e -- the envelope containing the message.
  1050. **
  1051. ** Returns:
  1052. ** none.
  1053. **
  1054. ** Side Effects:
  1055. ** outputs "p" to file "fp".
  1056. */
  1057. void
  1058. commaize(h, p, oldstyle, mci, e)
  1059. register HDR *h;
  1060. register char *p;
  1061. bool oldstyle;
  1062. register MCI *mci;
  1063. register ENVELOPE *e;
  1064. {
  1065. register char *obp;
  1066. int opos;
  1067. int omax;
  1068. bool firstone = TRUE;
  1069. char obuf[MAXLINE + 3];
  1070. /*
  1071. ** Output the address list translated by the
  1072. ** mailer and with commas.
  1073. */
  1074. if (tTd(14, 2))
  1075. printf("commaize(%s: %s)\n", h->h_field, p);
  1076. obp = obuf;
  1077. (void) sprintf(obp, "%s: ", h->h_field);
  1078. opos = strlen(h->h_field) + 2;
  1079. obp += opos;
  1080. omax = mci->mci_mailer->m_linelimit - 2;
  1081. if (omax < 0 || omax > 78)
  1082. omax = 78;
  1083. /*
  1084. ** Run through the list of values.
  1085. */
  1086. while (*p != '\0')
  1087. {
  1088. register char *name;
  1089. register int c;
  1090. char savechar;
  1091. int flags;
  1092. auto int stat;
  1093. /*
  1094. ** Find the end of the name. New style names
  1095. ** end with a comma, old style names end with
  1096. ** a space character. However, spaces do not
  1097. ** necessarily delimit an old-style name -- at
  1098. ** signs mean keep going.
  1099. */
  1100. /* find end of name */
  1101. while ((isascii(*p) && isspace(*p)) || *p == ',')
  1102. p++;
  1103. name = p;
  1104. for (;;)
  1105. {
  1106. auto char *oldp;
  1107. char pvpbuf[PSBUFSIZE];
  1108. (void) prescan(p, oldstyle ? ' ' : ',', pvpbuf,
  1109. sizeof pvpbuf, &oldp, NULL);
  1110. p = oldp;
  1111. /* look to see if we have an at sign */
  1112. while (*p != '\0' && isascii(*p) && isspace(*p))
  1113. p++;
  1114. if (*p != '@')
  1115. {
  1116. p = oldp;
  1117. break;
  1118. }
  1119. p += *p == '@' ? 1 : 2;
  1120. while (*p != '\0' && isascii(*p) && isspace(*p))
  1121. p++;
  1122. }
  1123. /* at the end of one complete name */
  1124. /* strip off trailing white space */
  1125. while (p >= name &&
  1126. ((isascii(*p) && isspace(*p)) || *p == ',' || *p == '\0'))
  1127. p--;
  1128. if (++p == name)
  1129. continue;
  1130. savechar = *p;
  1131. *p = '\0';
  1132. /* translate the name to be relative */
  1133. flags = RF_HEADERADDR|RF_ADDDOMAIN;
  1134. if (bitset(H_FROM, h->h_flags))
  1135. flags |= RF_SENDERADDR;
  1136. #if USERDB
  1137. else if (e->e_from.q_mailer != NULL &&
  1138. bitnset(M_UDBRECIPIENT, e->e_from.q_mailer->m_flags))
  1139. {
  1140. extern char *udbsender();
  1141. char *q;
  1142. q = udbsender(name);
  1143. if (q != NULL)
  1144. name = q;
  1145. }
  1146. #endif
  1147. stat = EX_OK;
  1148. name = remotename(name, mci->mci_mailer, flags, &stat, e);
  1149. if (*name == '\0')
  1150. {
  1151. *p = savechar;
  1152. continue;
  1153. }
  1154. /* output the name with nice formatting */
  1155. opos += strlen(name);
  1156. if (!firstone)
  1157. opos += 2;
  1158. if (opos > omax && !firstone)
  1159. {
  1160. (void) strcpy(obp, ",\n");
  1161. putline(obuf, mci);
  1162. obp = obuf;
  1163. (void) strcpy(obp, " ");
  1164. opos = strlen(obp);
  1165. obp += opos;
  1166. opos += strlen(name);
  1167. }
  1168. else if (!firstone)
  1169. {
  1170. (void) strcpy(obp, ", ");
  1171. obp += 2;
  1172. }
  1173. while ((c = *name++) != '\0' && obp < &obuf[MAXLINE])
  1174. *obp++ = c;
  1175. firstone = FALSE;
  1176. *p = savechar;
  1177. }
  1178. (void) strcpy(obp, "\n");
  1179. putline(obuf, mci);
  1180. }
  1181. /*
  1182. ** COPYHEADER -- copy header list
  1183. **
  1184. ** This routine is the equivalent of newstr for header lists
  1185. **
  1186. ** Parameters:
  1187. ** header -- list of header structures to copy.
  1188. **
  1189. ** Returns:
  1190. ** a copy of 'header'.
  1191. **
  1192. ** Side Effects:
  1193. ** none.
  1194. */
  1195. HDR *
  1196. copyheader(header)
  1197. register HDR *header;
  1198. {
  1199. register HDR *newhdr;
  1200. HDR *ret;
  1201. register HDR **tail = &ret;
  1202. while (header != NULL)
  1203. {
  1204. newhdr = (HDR *) xalloc(sizeof(HDR));
  1205. STRUCTCOPY(*header, *newhdr);
  1206. *tail = newhdr;
  1207. tail = &newhdr->h_link;
  1208. header = header->h_link;
  1209. }
  1210. *tail = NULL;
  1211. return ret;
  1212. }
  1213. #endif*/
  1214. //-----------------------------------------------------------------------------
  1215. // Description:
  1216. // Given a header, this function parses it for CRLF<LWSP> sequences
  1217. // unfolds it into a separate buffer, and returns the unfolded line. If
  1218. // the header passed in is not folded, no unfolded line is returned.
  1219. // Arguments:
  1220. // IN CHAR *pszHeader - The folded header. *MUST* be a NULL terminated
  1221. // string.
  1222. // OUT CHAR **ppszUnfolded - If pszValueBuf is not folded, NULL is
  1223. // returned otherwise a new buffer is allocated and pszValueBuf
  1224. // unfolded into the buffer, and the buffer is returned in this
  1225. // parameter. The buffer must be freed with FreeUnfoldedBuffer().
  1226. // Returns:
  1227. // TRUE on success.
  1228. // FALSE on out of memory errors.
  1229. //-----------------------------------------------------------------------------
  1230. BOOL UnfoldHeader(char *pszHeader, char **ppszUnfolded)
  1231. {
  1232. int cbHeader = 0;
  1233. BOOL fUnfold = FALSE;
  1234. *ppszUnfolded = NULL;
  1235. // Check for embedded CRLF<LWSP> AND get length of pszHeader at the same time
  1236. for(cbHeader = 0; pszHeader[cbHeader]; cbHeader++)
  1237. {
  1238. if(!fUnfold &&
  1239. pszHeader[cbHeader] == '\r' &&
  1240. (pszHeader[cbHeader + 1] &&
  1241. pszHeader[cbHeader + 1] == '\n') &&
  1242. (pszHeader[cbHeader + 2] &&
  1243. (pszHeader[cbHeader + 2] == ' ' || pszHeader[cbHeader + 2] == '\t')))
  1244. {
  1245. fUnfold = TRUE;
  1246. }
  1247. }
  1248. if(!fUnfold)
  1249. return TRUE;
  1250. *ppszUnfolded = new char[cbHeader + 1];
  1251. if(!*ppszUnfolded)
  1252. return FALSE;
  1253. //
  1254. // Copy pszHeader to *ppszUnfolded while skipping CRLF<LWSP> sequences
  1255. //
  1256. int i = 0;
  1257. int j = 0;
  1258. while(j < cbHeader)
  1259. {
  1260. if(pszHeader[j] == '\r' && (j+1 < cbHeader && pszHeader[j+1] == '\n'))
  1261. {
  1262. j += 2; // skip the CRLF we found
  1263. while(j < cbHeader && (pszHeader[j] == ' ' || pszHeader[j] == '\t'))
  1264. j++; // skip LWSP
  1265. if(j >= cbHeader)
  1266. break;
  1267. }
  1268. (*ppszUnfolded)[i++] = pszHeader[j++];
  1269. }
  1270. _ASSERT(i < cbHeader);
  1271. (*ppszUnfolded)[i] = '\0';
  1272. return TRUE;
  1273. }
  1274. void FreeUnfoldedHeader(char *pszHeader)
  1275. {
  1276. delete [] pszHeader;
  1277. }