1*e89934bbSchristos /* $NetBSD: header_opts.c,v 1.2 2017/02/14 01:16:45 christos Exp $ */
241fbaed0Stron
341fbaed0Stron /*++
441fbaed0Stron /* NAME
541fbaed0Stron /* header_opts 3
641fbaed0Stron /* SUMMARY
741fbaed0Stron /* message header classification
841fbaed0Stron /* SYNOPSIS
941fbaed0Stron /* #include <header_opts.h>
1041fbaed0Stron /*
1141fbaed0Stron /* const HEADER_OPTS *header_opts_find(string)
1241fbaed0Stron /* const char *string;
1341fbaed0Stron /* DESCRIPTION
1441fbaed0Stron /* header_opts_find() takes a message header line and looks up control
1541fbaed0Stron /* information for the corresponding header type.
1641fbaed0Stron /* DIAGNOSTICS
1741fbaed0Stron /* Panic: input is not a valid header line. The result is a pointer
1841fbaed0Stron /* to HEADER_OPTS in case of success, a null pointer when the header
1941fbaed0Stron /* label was not recognized.
2041fbaed0Stron /* SEE ALSO
2141fbaed0Stron /* header_opts(3h) the gory details
2241fbaed0Stron /* LICENSE
2341fbaed0Stron /* .ad
2441fbaed0Stron /* .fi
2541fbaed0Stron /* The Secure Mailer license must be distributed with this software.
2641fbaed0Stron /* AUTHOR(S)
2741fbaed0Stron /* Wietse Venema
2841fbaed0Stron /* IBM T.J. Watson Research
2941fbaed0Stron /* P.O. Box 704
3041fbaed0Stron /* Yorktown Heights, NY 10598, USA
3141fbaed0Stron /*--*/
3241fbaed0Stron
3341fbaed0Stron /* System library. */
3441fbaed0Stron
3541fbaed0Stron #include <sys_defs.h>
3641fbaed0Stron #include <ctype.h>
3741fbaed0Stron
3841fbaed0Stron /* Utility library. */
3941fbaed0Stron
4041fbaed0Stron #include <msg.h>
4141fbaed0Stron #include <htable.h>
4241fbaed0Stron #include <vstring.h>
4341fbaed0Stron #include <stringops.h>
44e262b48eSchristos #include <argv.h>
45e262b48eSchristos #include <mymalloc.h>
4641fbaed0Stron
4741fbaed0Stron /* Global library. */
4841fbaed0Stron
49e262b48eSchristos #include <mail_params.h>
50e262b48eSchristos #include <header_opts.h>
5141fbaed0Stron
5241fbaed0Stron /*
5341fbaed0Stron * Header names are given in the preferred capitalization. The lookups are
5441fbaed0Stron * case-insensitive.
5541fbaed0Stron *
5641fbaed0Stron * XXX Removing Return-Path: headers should probably be done only with mail
5741fbaed0Stron * that enters via a non-SMTP channel. Changing this now could break other
5841fbaed0Stron * software. See also comments in bounce_notify_util.c.
5941fbaed0Stron */
60e262b48eSchristos static HEADER_OPTS header_opts[] = {
6141fbaed0Stron "Apparently-To", HDR_APPARENTLY_TO, HDR_OPT_RECIP,
62e262b48eSchristos "Bcc", HDR_BCC, HDR_OPT_XRECIP,
6341fbaed0Stron "Cc", HDR_CC, HDR_OPT_XRECIP,
6441fbaed0Stron "Content-Description", HDR_CONTENT_DESCRIPTION, HDR_OPT_MIME,
6541fbaed0Stron "Content-Disposition", HDR_CONTENT_DISPOSITION, HDR_OPT_MIME,
6641fbaed0Stron "Content-ID", HDR_CONTENT_ID, HDR_OPT_MIME,
67e262b48eSchristos "Content-Length", HDR_CONTENT_LENGTH, 0,
6841fbaed0Stron "Content-Transfer-Encoding", HDR_CONTENT_TRANSFER_ENCODING, HDR_OPT_MIME,
6941fbaed0Stron "Content-Type", HDR_CONTENT_TYPE, HDR_OPT_MIME,
7041fbaed0Stron "Delivered-To", HDR_DELIVERED_TO, 0,
7141fbaed0Stron "Disposition-Notification-To", HDR_DISP_NOTIFICATION, HDR_OPT_SENDER,
7241fbaed0Stron "Date", HDR_DATE, 0,
7341fbaed0Stron "Errors-To", HDR_ERRORS_TO, HDR_OPT_SENDER,
7441fbaed0Stron "From", HDR_FROM, HDR_OPT_SENDER,
7541fbaed0Stron "Mail-Followup-To", HDR_MAIL_FOLLOWUP_TO, HDR_OPT_SENDER,
7641fbaed0Stron "Message-Id", HDR_MESSAGE_ID, 0,
7741fbaed0Stron "MIME-Version", HDR_MIME_VERSION, HDR_OPT_MIME,
7841fbaed0Stron "Received", HDR_RECEIVED, 0,
7941fbaed0Stron "Reply-To", HDR_REPLY_TO, HDR_OPT_SENDER,
80e262b48eSchristos "Resent-Bcc", HDR_RESENT_BCC, HDR_OPT_XRECIP | HDR_OPT_RR,
8141fbaed0Stron "Resent-Cc", HDR_RESENT_CC, HDR_OPT_XRECIP | HDR_OPT_RR,
8241fbaed0Stron "Resent-Date", HDR_RESENT_DATE, HDR_OPT_RR,
8341fbaed0Stron "Resent-From", HDR_RESENT_FROM, HDR_OPT_SENDER | HDR_OPT_RR,
8441fbaed0Stron "Resent-Message-Id", HDR_RESENT_MESSAGE_ID, HDR_OPT_RR,
8541fbaed0Stron "Resent-Reply-To", HDR_RESENT_REPLY_TO, HDR_OPT_RECIP | HDR_OPT_RR,
8641fbaed0Stron "Resent-Sender", HDR_RESENT_SENDER, HDR_OPT_SENDER | HDR_OPT_RR,
8741fbaed0Stron "Resent-To", HDR_RESENT_TO, HDR_OPT_XRECIP | HDR_OPT_RR,
88e262b48eSchristos "Return-Path", HDR_RETURN_PATH, HDR_OPT_SENDER,
8941fbaed0Stron "Return-Receipt-To", HDR_RETURN_RECEIPT_TO, HDR_OPT_SENDER,
9041fbaed0Stron "Sender", HDR_SENDER, HDR_OPT_SENDER,
9141fbaed0Stron "To", HDR_TO, HDR_OPT_XRECIP,
9241fbaed0Stron };
9341fbaed0Stron
9441fbaed0Stron #define HEADER_OPTS_SIZE (sizeof(header_opts) / sizeof(header_opts[0]))
9541fbaed0Stron
9641fbaed0Stron static HTABLE *header_hash; /* quick lookup */
9741fbaed0Stron static VSTRING *header_key;
9841fbaed0Stron
9941fbaed0Stron /* header_opts_init - initialize */
10041fbaed0Stron
header_opts_init(void)10141fbaed0Stron static void header_opts_init(void)
10241fbaed0Stron {
10341fbaed0Stron const HEADER_OPTS *hp;
10441fbaed0Stron const char *cp;
10541fbaed0Stron
10641fbaed0Stron /*
10741fbaed0Stron * Build a hash table for quick lookup, and allocate memory for
10841fbaed0Stron * lower-casing the lookup key.
10941fbaed0Stron */
11041fbaed0Stron header_key = vstring_alloc(10);
11141fbaed0Stron header_hash = htable_create(HEADER_OPTS_SIZE);
11241fbaed0Stron for (hp = header_opts; hp < header_opts + HEADER_OPTS_SIZE; hp++) {
11341fbaed0Stron VSTRING_RESET(header_key);
11441fbaed0Stron for (cp = hp->name; *cp; cp++)
11541fbaed0Stron VSTRING_ADDCH(header_key, TOLOWER(*cp));
11641fbaed0Stron VSTRING_TERMINATE(header_key);
117e262b48eSchristos htable_enter(header_hash, vstring_str(header_key), (void *) hp);
11841fbaed0Stron }
11941fbaed0Stron }
12041fbaed0Stron
121e262b48eSchristos /* header_drop_init - initialize "header drop" flags */
122e262b48eSchristos
header_drop_init(void)123e262b48eSchristos static void header_drop_init(void)
124e262b48eSchristos {
125e262b48eSchristos ARGV *hdr_drop_list;
126e262b48eSchristos char **cpp;
127e262b48eSchristos HTABLE_INFO *ht;
128e262b48eSchristos HEADER_OPTS *hp;
129e262b48eSchristos
130e262b48eSchristos /*
131e262b48eSchristos * Having one main.cf parameter for the "drop" header flag does not
132e262b48eSchristos * generalize to the "sender", "extract", etc., flags. Flags would need
133e262b48eSchristos * to be grouped by header name, but that would be unwieldy, too:
134e262b48eSchristos *
135e262b48eSchristos * message_header_flags = { apparently-to = recipient }, { bcc = recipient,
136e262b48eSchristos * extract, drop }, { from = sender }, ...
137e262b48eSchristos *
138e262b48eSchristos * Thus, it is unlikely that all header flags will become configurable.
139e262b48eSchristos */
140e262b48eSchristos hdr_drop_list = argv_split(var_drop_hdrs, CHARS_COMMA_SP);
141e262b48eSchristos for (cpp = hdr_drop_list->argv; *cpp; cpp++) {
142e262b48eSchristos lowercase(*cpp);
143e262b48eSchristos if ((ht = htable_locate(header_hash, *cpp)) == 0) {
144e262b48eSchristos hp = (HEADER_OPTS *) mymalloc(sizeof(*hp));
145e262b48eSchristos hp->type = HDR_OTHER;
146e262b48eSchristos hp->flags = HDR_OPT_DROP;
147e262b48eSchristos ht = htable_enter(header_hash, *cpp, (void *) hp);
148e262b48eSchristos hp->name = ht->key;
149e262b48eSchristos } else
150e262b48eSchristos hp = (HEADER_OPTS *) ht->value;
151e262b48eSchristos hp->flags |= HDR_OPT_DROP;
152e262b48eSchristos }
153e262b48eSchristos argv_free(hdr_drop_list);
154e262b48eSchristos }
155e262b48eSchristos
15641fbaed0Stron /* header_opts_find - look up header options */
15741fbaed0Stron
header_opts_find(const char * string)15841fbaed0Stron const HEADER_OPTS *header_opts_find(const char *string)
15941fbaed0Stron {
16041fbaed0Stron const char *cp;
16141fbaed0Stron
162e262b48eSchristos if (header_hash == 0) {
16341fbaed0Stron header_opts_init();
164e262b48eSchristos header_drop_init();
165e262b48eSchristos }
16641fbaed0Stron
16741fbaed0Stron /*
16841fbaed0Stron * Look up the lower-cased version of the header name.
16941fbaed0Stron */
17041fbaed0Stron VSTRING_RESET(header_key);
17141fbaed0Stron for (cp = string; *cp != ':'; cp++) {
17241fbaed0Stron if (*cp == 0)
17341fbaed0Stron msg_panic("header_opts_find: no colon in header: %.30s", string);
17441fbaed0Stron VSTRING_ADDCH(header_key, TOLOWER(*cp));
17541fbaed0Stron }
17641fbaed0Stron vstring_truncate(header_key,
17741fbaed0Stron trimblanks(vstring_str(header_key), cp - string)
17841fbaed0Stron - vstring_str(header_key));
17941fbaed0Stron VSTRING_TERMINATE(header_key);
18041fbaed0Stron return ((const HEADER_OPTS *) htable_find(header_hash, vstring_str(header_key)));
18141fbaed0Stron }
182