1/*	$NetBSD$	*/
2
3/*++
4/* NAME
5/*	delivered_hdr 3
6/* SUMMARY
7/*	process Delivered-To: headers
8/* SYNOPSIS
9/*	#include <delivered_hdr.h>
10/*
11/*	DELIVERED_HDR_INFO *delivered_hdr_init(stream, offset, flags)
12/*	VSTREAM	*stream;
13/*	off_t	offset;
14/*	int	flags;
15/*
16/*	int	delivered_hdr_find(info, address)
17/*	DELIVERED_HDR_INFO *info;
18/*	const char *address;
19/*
20/*	void	delivered_hdr_free(info)
21/*	DELIVERED_HDR_INFO *info;
22/* DESCRIPTION
23/*	This module processes addresses in Delivered-To: headers.
24/*	These headers are added by some mail delivery systems, for the
25/*	purpose of breaking mail forwarding loops. N.B. This solves
26/*	a different problem than the Received: hop count limit. Hop
27/*	counts are used to limit the impact of mail routing problems.
28/*
29/*	delivered_hdr_init() extracts Delivered-To: header addresses
30/*	from the specified message, and returns a table with the
31/*	result. The file seek pointer is changed.
32/*
33/*	delivered_hdr_find() looks up the address in the lookup table,
34/*	and returns non-zero when the address was found. The
35/*	address argument must be in internalized form.
36/*
37/*	delivered_hdr_free() releases storage that was allocated by
38/*	delivered_hdr_init().
39/*
40/*	Arguments:
41/* .IP stream
42/*	The open queue file.
43/* .IP offset
44/*	Offset of the first message content record.
45/* .IP flags
46/*	Zero, or the bit-wise OR ot:
47/* .RS
48/* .IP FOLD_ADDR_USER
49/*	Case fold the address local part.
50/* .IP FOLD_ADDR_HOST
51/*	Case fold the address domain part.
52/* .IP FOLD_ADDR_ALL
53/*	Alias for (FOLD_ADDR_USER | FOLD_ADDR_HOST).
54/* .RE
55/* .IP info
56/*	Extracted Delivered-To: addresses information.
57/* .IP address
58/*	A recipient address, internal form.
59/* DIAGNOSTICS
60/*	Fatal errors: out of memory.
61/* SEE ALSO
62/*	mail_copy(3), producer of Delivered-To: and other headers.
63/* LICENSE
64/* .ad
65/* .fi
66/*	The Secure Mailer license must be distributed with this software.
67/* AUTHOR(S)
68/*	Wietse Venema
69/*	IBM T.J. Watson Research
70/*	P.O. Box 704
71/*	Yorktown Heights, NY 10598, USA
72/*--*/
73
74/* System library. */
75
76#include <sys_defs.h>
77#include <unistd.h>
78#include <string.h>
79#include <ctype.h>
80
81/* Utility library. */
82
83#include <msg.h>
84#include <mymalloc.h>
85#include <htable.h>
86#include <vstring.h>
87#include <vstream.h>
88#include <vstring_vstream.h>
89#include <stringops.h>
90
91/* Global library. */
92
93#include <record.h>
94#include <rec_type.h>
95#include <is_header.h>
96#include <quote_822_local.h>
97#include <header_opts.h>
98#include <delivered_hdr.h>
99#include <fold_addr.h>
100
101 /*
102  * Application-specific.
103  */
104struct DELIVERED_HDR_INFO {
105    int     flags;
106    VSTRING *buf;
107    HTABLE *table;
108};
109
110#define STR(x) vstring_str(x)
111
112/* delivered_hdr_init - extract delivered-to information from the message */
113
114DELIVERED_HDR_INFO *delivered_hdr_init(VSTREAM *fp, off_t offset, int flags)
115{
116    char   *cp;
117    DELIVERED_HDR_INFO *info;
118    const HEADER_OPTS *hdr;
119
120    /*
121     * Sanity check.
122     */
123    info = (DELIVERED_HDR_INFO *) mymalloc(sizeof(*info));
124    info->flags = flags;
125    info->buf = vstring_alloc(10);
126    info->table = htable_create(0);
127
128    if (vstream_fseek(fp, offset, SEEK_SET) < 0)
129	msg_fatal("seek queue file %s: %m", VSTREAM_PATH(fp));
130
131    /*
132     * XXX Assume that mail_copy() produces delivered-to headers that fit in
133     * a REC_TYPE_NORM record. Lowercase the delivered-to addresses for
134     * consistency.
135     *
136     * XXX Don't get bogged down by gazillions of delivered-to headers.
137     */
138#define DELIVERED_HDR_LIMIT	1000
139
140    while (rec_get(fp, info->buf, 0) == REC_TYPE_NORM
141	   && info->table->used < DELIVERED_HDR_LIMIT) {
142	if (is_header(STR(info->buf))) {
143	    if ((hdr = header_opts_find(STR(info->buf))) != 0
144		&& hdr->type == HDR_DELIVERED_TO) {
145		cp = STR(info->buf) + strlen(hdr->name) + 1;
146		while (ISSPACE(*cp))
147		    cp++;
148		if (info->flags & FOLD_ADDR_ALL)
149		    fold_addr(cp, info->flags);
150		if (msg_verbose)
151		    msg_info("delivered_hdr_init: %s", cp);
152		htable_enter(info->table, cp, (char *) 0);
153	    }
154	} else if (ISSPACE(STR(info->buf)[0])) {
155	    continue;
156	} else {
157	    break;
158	}
159    }
160    return (info);
161}
162
163/* delivered_hdr_find - look up recipient in delivered table */
164
165int     delivered_hdr_find(DELIVERED_HDR_INFO *info, const char *address)
166{
167    HTABLE_INFO *ht;
168
169    /*
170     * mail_copy() uses quote_822_local() when writing the Delivered-To:
171     * header. We must therefore apply the same transformation when looking
172     * up the recipient. Lowercase the delivered-to address for consistency.
173     */
174    quote_822_local(info->buf, address);
175    if (info->flags & FOLD_ADDR_ALL)
176	fold_addr(STR(info->buf), info->flags);
177    ht = htable_locate(info->table, STR(info->buf));
178    return (ht != 0);
179}
180
181/* delivered_hdr_free - destructor */
182
183void    delivered_hdr_free(DELIVERED_HDR_INFO *info)
184{
185    vstring_free(info->buf);
186    htable_free(info->table, (void (*) (char *)) 0);
187    myfree((char *) info);
188}
189