masqmail
view src/alias.c @ 378:5781ba87df95
Removed ident. This had been discussed on the mailing list in Oct 2011.
Ident is hardly useful in typical setups for masqmail. Probably Oliver
had used it in his setup; that would make sense. Now, I know of nobody
who needs it.
author | markus schnalke <meillo@marmaro.de> |
---|---|
date | Sat, 14 Jan 2012 21:36:58 +0100 |
parents | b27f66555ba8 |
children | a408411ff8df |
line source
1 /*
2 ** MasqMail
3 ** Copyright (C) 2000-2001 Oliver Kurth
4 ** Copyright (C) 2010 markus schnalke <meillo@marmaro.de>
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
21 #include "masqmail.h"
22 #include <fnmatch.h>
24 gboolean
25 addr_is_local(address *addr)
26 {
27 GList *dom_node;
28 GList *addr_node;
29 address *a;
31 if (addr->domain == NULL) {
32 return TRUE;
33 }
34 foreach(conf.local_hosts, dom_node) {
35 /* Note: FNM_CASEFOLD is a GNU extension */
36 if (fnmatch(dom_node->data, addr->domain, FNM_CASEFOLD) != 0) {
37 /* no match, try next */
38 continue;
39 }
40 foreach(conf.not_local_addresses, addr_node) {
41 a = create_address_qualified(addr_node->data, TRUE, conf.host_name);
42 DEBUG(6) debugf("not_local_addresses: addr_node->data=%s a->address=%s\n",
43 addr_node->data, a->address);
44 if (addr_isequal(a, addr, conf.localpartcmp)) {
45 destroy_address(a);
46 /* in local_hosts but also in not_local_addresses */
47 return FALSE;
48 }
49 destroy_address(a);
50 }
51 /* in local_hosts */
52 return TRUE;
53 }
54 foreach(conf.local_addresses, addr_node) {
55 a = create_address_qualified(addr_node->data, TRUE, conf.host_name);
56 DEBUG(6) debugf("local_addresses: addr_node->data=%s a->address=%s\n",
57 addr_node->data, a->address);
58 if (addr_isequal(a, addr, conf.localpartcmp)) {
59 destroy_address(a);
60 /* in local_addresses */
61 return TRUE;
62 }
63 destroy_address(a);
64 }
65 return FALSE;
66 }
68 static GList*
69 parse_list(gchar *line)
70 {
71 GList *list = NULL;
72 gchar buf[256];
73 gchar *p, *q;
75 p = line;
76 while (*p != '\0') {
77 q = buf;
78 while (isspace(*p))
79 p++;
80 if (*p != '"') {
81 while (*p && (*p != ',') && (q < buf + 255))
82 *(q++) = *(p++);
83 *q = '\0';
84 } else {
85 gboolean escape = FALSE;
86 p++;
87 while (*p && (*p != '"' || escape) && (q < buf + 255)) {
88 if ((*p == '\\') && !escape)
89 escape = TRUE;
90 else {
91 escape = FALSE;
92 *(q++) = *p;
93 }
94 p++;
95 }
96 *q = '\0';
97 while (*p && (*p != ','))
98 p++;
99 }
100 list = g_list_append(list, g_strdup(g_strchomp(buf)));
101 if (*p)
102 p++;
103 }
104 return list;
105 }
107 /*
108 ** addr is assumed to be local and no pipe address nor not-to-expand
109 */
110 static GList*
111 expand_one(GList *alias_table, address *addr)
112 {
113 GList *val_list;
114 GList *val_node;
115 GList *alias_list = NULL;
116 GList *alias_node;
117 gchar *val;
119 /* expand the local alias */
120 DEBUG(6) debugf("alias: '%s' is local and will get expanded\n", addr->local_part);
122 if (strcasecmp(addr->local_part, "postmaster") == 0) {
123 /*
124 ** postmaster must always be matched caseless
125 ** see RFC 822 and RFC 5321
126 */
127 val = (gchar *) table_find_func(alias_table, addr->local_part, strcasecmp);
128 } else {
129 val = (gchar *) table_find_func(alias_table, addr->local_part, conf.localpartcmp);
130 }
131 if (!val) {
132 DEBUG(5) debugf("alias: '%s' is fully expanded, hence completed\n",
133 addr->local_part);
134 return g_list_append(NULL, addr);
135 }
137 DEBUG(5) debugf("alias: '%s' -> '%s'\n", addr->local_part, val);
138 val_list = parse_list(val);
139 alias_list = NULL;
141 foreach(val_list, val_node) {
142 gchar *val = (gchar *) (val_node->data);
143 address *alias_addr;
145 DEBUG(6) debugf("alias: processing '%s'\n", val);
147 if (val[0] == '\\') {
148 DEBUG(5) debugf("alias: '%s' is marked as final, hence completed\n", val);
149 alias_addr = create_address_qualified(val+1, TRUE, conf.host_name);
150 g_free(val);
151 DEBUG(6) debugf("alias: address generated: '%s'\n",
152 alias_addr->local_part);
153 alias_list = g_list_append(alias_list, alias_addr);
154 continue;
155 }
157 if (val[0] == '|') {
158 DEBUG(5) debugf("alias: '%s' is a pipe address\n", val);
159 alias_addr = create_address_pipe(val);
160 g_free(val);
161 DEBUG(6) debugf("alias: pipe generated: %s\n",
162 alias_addr->local_part);
163 alias_list = g_list_append(alias_list, alias_addr);
164 continue;
165 }
167 alias_addr = create_address_qualified(val, TRUE, conf.host_name);
168 g_free(val);
170 if (!addr_is_local(alias_addr)) {
171 DEBUG(5) debugf("alias: '%s@%s' is non-local, hence completed\n",
172 alias_addr->local_part, alias_addr->domain);
173 alias_list = g_list_append(alias_list, alias_addr);
174 continue;
175 }
177 /* addr is local and to expand at this point */
178 /* but first ... search in parents for loops: */
179 if (addr_isequal_parent(addr, alias_addr, conf.localpartcmp)) {
180 /* loop detected, ignore this path */
181 logwrite(LOG_ALERT, "alias: detected loop, hence ignoring '%s'\n",
182 alias_addr->local_part);
183 continue;
184 }
185 alias_addr->parent = addr;
187 /* recurse */
188 DEBUG(6) debugf("alias: >>\n");
189 alias_node = expand_one(alias_table, alias_addr);
190 DEBUG(6) debugf("alias: <<\n");
191 if (alias_node) {
192 alias_list = g_list_concat(alias_list, alias_node);
193 }
194 }
195 g_list_free(val_list);
196 addr->children = g_list_copy(alias_list);
198 return alias_list;
199 }
201 GList*
202 alias_expand(GList *alias_table, GList *rcpt_list, GList *non_rcpt_list)
203 {
204 GList *rcpt_node = NULL;
205 GList *alias_list = NULL;
206 GList *done_list = NULL;
207 GList *rcpt_node_next = NULL;
208 address *addr = NULL;
210 for (rcpt_node=g_list_copy(rcpt_list);
211 rcpt_node;
212 rcpt_node=g_list_next(rcpt_node)) {
214 addr = (address *) (rcpt_node->data);
215 if (addr_is_local(addr)) {
216 DEBUG(5) debugf("alias: (orig rcpt addr) expand local '%s'\n",
217 addr->local_part);
218 alias_list = expand_one(alias_table, addr);
219 if (alias_list) {
220 done_list = g_list_concat(done_list, alias_list);
221 }
222 } else {
223 DEBUG(5) debugf("alias: (orig rcpt addr) don't expand non-local '%s@%s'\n",
224 addr->local_part, addr->domain);
225 done_list = g_list_append(done_list, addr);
226 }
227 }
229 /* we're done if we don't have to remove rcpts */
230 if (!non_rcpt_list) {
231 return done_list;
232 }
234 /* delete addresses of non_rcpt_list from done_list */
235 for (rcpt_node = g_list_first(done_list); rcpt_node; rcpt_node = rcpt_node_next) {
236 address *addr = (address *) (rcpt_node->data);
237 GList *non_node;
239 rcpt_node_next = g_list_next(rcpt_node);
240 foreach(non_rcpt_list, non_node) {
241 address *non_addr = (address *) (non_node->data);
242 if (addr_isequal(addr, non_addr, conf.localpartcmp)) {
243 done_list = g_list_remove_link(done_list, rcpt_node);
244 g_list_free_1(rcpt_node);
245 /*
246 ** this address is still in the children
247 ** lists of the original address, simply
248 ** mark them delivered
249 */
250 addr_mark_delivered(addr);
251 break;
252 }
253 }
254 }
255 return done_list;
256 }