summaryrefslogtreecommitdiffstats
path: root/src/global/delivered_hdr.c
blob: f34a9c715918804505c74ebe7c4055e63b636b80 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/*++
/* NAME
/*	delivered_hdr 3
/* SUMMARY
/*	process Delivered-To: headers
/* SYNOPSIS
/*	#include <delivered_hdr.h>
/*
/*	DELIVERED_HDR_INFO *delivered_hdr_init(stream, offset, flags)
/*	VSTREAM	*stream;
/*	off_t	offset;
/*	int	flags;
/*
/*	int	delivered_hdr_find(info, address)
/*	DELIVERED_HDR_INFO *info;
/*	const char *address;
/*
/*	void	delivered_hdr_free(info)
/*	DELIVERED_HDR_INFO *info;
/* DESCRIPTION
/*	This module processes addresses in Delivered-To: headers.
/*	These headers are added by some mail delivery systems, for the
/*	purpose of breaking mail forwarding loops. N.B. This solves
/*	a different problem than the Received: hop count limit. Hop
/*	counts are used to limit the impact of mail routing problems.
/*
/*	delivered_hdr_init() extracts Delivered-To: header addresses
/*	from the specified message, and returns a table with the
/*	result. The file seek pointer is changed.
/*
/*	delivered_hdr_find() looks up the address in the lookup table,
/*	and returns non-zero when the address was found. The
/*	address argument must be in internalized form.
/*
/*	delivered_hdr_free() releases storage that was allocated by
/*	delivered_hdr_init().
/*
/*	Arguments:
/* .IP stream
/*	The open queue file.
/* .IP offset
/*	Offset of the first message content record.
/* .IP flags
/*	Zero, or the bit-wise OR ot:
/* .RS
/* .IP FOLD_ADDR_USER
/*	Case fold the address local part.
/* .IP FOLD_ADDR_HOST
/*	Case fold the address domain part.
/* .IP FOLD_ADDR_ALL
/*	Alias for (FOLD_ADDR_USER | FOLD_ADDR_HOST).
/* .RE
/* .IP info
/*	Extracted Delivered-To: addresses information.
/* .IP address
/*	A recipient address, internal form.
/* DIAGNOSTICS
/*	Fatal errors: out of memory.
/* SEE ALSO
/*	mail_copy(3), producer of Delivered-To: and other headers.
/* LICENSE
/* .ad
/* .fi
/*	The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/*	Wietse Venema
/*	IBM T.J. Watson Research
/*	P.O. Box 704
/*	Yorktown Heights, NY 10598, USA
/*--*/

/* System library. */

#include <sys_defs.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>

/* Utility library. */

#include <msg.h>
#include <mymalloc.h>
#include <htable.h>
#include <vstring.h>
#include <vstream.h>
#include <vstring_vstream.h>
#include <stringops.h>

/* Global library. */

#include <record.h>
#include <rec_type.h>
#include <is_header.h>
#include <quote_822_local.h>
#include <header_opts.h>
#include <delivered_hdr.h>
#include <fold_addr.h>

 /*
  * Application-specific.
  */
struct DELIVERED_HDR_INFO {
    int     flags;
    VSTRING *buf;
    VSTRING *fold;
    HTABLE *table;
};

#define STR(x) vstring_str(x)

/* delivered_hdr_init - extract delivered-to information from the message */

DELIVERED_HDR_INFO *delivered_hdr_init(VSTREAM *fp, off_t offset, int flags)
{
    char   *cp;
    DELIVERED_HDR_INFO *info;
    const HEADER_OPTS *hdr;
    int     curr_type;
    int     prev_type;

    /*
     * Sanity check.
     */
    info = (DELIVERED_HDR_INFO *) mymalloc(sizeof(*info));
    info->flags = flags;
    info->buf = vstring_alloc(10);
    info->fold = vstring_alloc(10);
    info->table = htable_create(0);

    if (vstream_fseek(fp, offset, SEEK_SET) < 0)
	msg_fatal("seek queue file %s: %m", VSTREAM_PATH(fp));

    /*
     * XXX Assume that mail_copy() produces delivered-to headers that fit in
     * a REC_TYPE_NORM or REC_TYPE_CONT record. Lowercase the delivered-to
     * addresses for consistency.
     * 
     * XXX Don't get bogged down by gazillions of delivered-to headers.
     */
#define DELIVERED_HDR_LIMIT	1000

    for (prev_type = REC_TYPE_NORM;
	 info->table->used < DELIVERED_HDR_LIMIT
	 && ((curr_type = rec_get(fp, info->buf, 0)) == REC_TYPE_NORM
	     || curr_type == REC_TYPE_CONT);
	 prev_type = curr_type) {
	if (prev_type != REC_TYPE_NORM)
	    continue;
	if (is_header(STR(info->buf))) {
	    if ((hdr = header_opts_find(STR(info->buf))) != 0
		&& hdr->type == HDR_DELIVERED_TO) {
		cp = STR(info->buf) + strlen(hdr->name) + 1;
		while (ISSPACE(*cp))
		    cp++;
		cp = fold_addr(info->fold, cp, info->flags);
		if (msg_verbose)
		    msg_info("delivered_hdr_init: %s", cp);
		htable_enter(info->table, cp, (void *) 0);
	    }
	} else if (ISSPACE(STR(info->buf)[0])) {
	    continue;
	} else {
	    break;
	}
    }
    return (info);
}

/* delivered_hdr_find - look up recipient in delivered table */

int     delivered_hdr_find(DELIVERED_HDR_INFO *info, const char *address)
{
    HTABLE_INFO *ht;
    const char *addr_key;

    /*
     * mail_copy() uses quote_822_local() when writing the Delivered-To:
     * header. We must therefore apply the same transformation when looking
     * up the recipient. Lowercase the delivered-to address for consistency.
     */
    quote_822_local(info->buf, address);
    addr_key = fold_addr(info->fold, STR(info->buf), info->flags);
    ht = htable_locate(info->table, addr_key);
    return (ht != 0);
}

/* delivered_hdr_free - destructor */

void    delivered_hdr_free(DELIVERED_HDR_INFO *info)
{
    vstring_free(info->buf);
    vstring_free(info->fold);
    htable_free(info->table, (void (*) (void *)) 0);
    myfree((void *) info);
}