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