masqmail
view src/alias.c @ 156:ee2afbf92428
require host_name to be set in config file
exit otherwise
there is no portable way to determine the hostname
(actually the hostname that masqmail should use)
thus it must be set by the administrator
author | meillo@marmaro.de |
---|---|
date | Thu, 08 Jul 2010 09:49:05 +0200 |
parents | a8f3424347dc |
children | 3f33a0feeeb0 |
line source
1 /* MasqMail
2 Copyright (C) 2000-2001 Oliver Kurth
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
19 #include "masqmail.h"
20 #include <fnmatch.h>
22 gboolean
23 addr_is_local(address * addr)
24 {
25 GList *dom_node;
26 GList *addr_node;
27 address *a;
29 foreach(conf.local_hosts, dom_node) {
30 if (addr->domain == NULL)
31 return TRUE;
32 if (fnmatch(dom_node->data, addr->domain, FNM_CASEFOLD) == 0) {
33 foreach(conf.not_local_addresses, addr_node) {
34 a = create_address_qualified(addr_node->data, TRUE, conf.host_name);
35 DEBUG(6) debugf("not_local_addresses: addr_node->data=%s a->address=%s\n",
36 addr_node->data, a->address);
37 if (addr_isequal(a, addr)) {
38 destroy_address(a);
39 return FALSE;
40 }
41 destroy_address(a);
42 }
43 return TRUE;
44 }
45 }
46 foreach(conf.local_addresses, addr_node) {
47 a = create_address_qualified(addr_node->data, TRUE, conf.host_name);
48 DEBUG(6) debugf("local_addresses: addr_node->data=%s a->address=%s\n",
49 addr_node->data, a->address);
50 if (addr_isequal(a, addr)) {
51 destroy_address(a);
52 return TRUE;
53 }
54 destroy_address(a);
55 }
56 return FALSE;
57 }
59 static gboolean
60 addr_isequal_alias(address * addr1, address * addr2)
61 {
62 return (conf.alias_local_cmp(addr1->local_part, addr2->local_part) == 0)
63 && (strcasecmp(addr1->domain, addr2->domain) == 0);
64 }
66 static GList*
67 parse_list(gchar * line)
68 {
69 GList *list = NULL;
70 gchar buf[256];
71 gchar *p, *q;
73 p = line;
74 while (*p != '\0') {
75 q = buf;
76 while (isspace(*p))
77 p++;
78 if (*p != '\"') {
79 while (*p && (*p != ',') && (q < buf + 255))
80 *(q++) = *(p++);
81 *q = '\0';
82 } else {
83 gboolean escape = FALSE;
84 p++;
85 while (*p && (*p != '\"' || escape) && (q < buf + 255)) {
86 if ((*p == '\\') && !escape)
87 escape = TRUE;
88 else {
89 escape = FALSE;
90 *(q++) = *p;
91 }
92 p++;
93 }
94 *q = '\0';
95 while (*p && (*p != ','))
96 p++;
97 }
98 list = g_list_append(list, g_strdup(g_strchomp(buf)));
99 if (*p)
100 p++;
101 }
102 return list;
103 }
105 GList*
106 alias_expand(GList * alias_table, GList * rcpt_list, GList * non_rcpt_list)
107 {
108 GList *done_list = NULL;
109 GList *rcpt_node = g_list_copy(rcpt_list);
111 while (rcpt_node != NULL) {
112 address *addr = (address *) (rcpt_node->data);
113 DEBUG(5) debugf("alias_expand begin: '%s@%s'\n", addr->local_part, addr->domain);
114 /* if(addr_is_local(addr) && (addr->local_part[0] != '|') && */
115 if (addr_is_local(addr) && !(addr->flags & ADDR_FLAG_NOEXPAND)) {
116 gchar *val;
118 /* special handling for postmaster */
119 if (strcasecmp(addr->local_part, "postmaster") == 0)
120 val = (gchar *) table_find_func(alias_table, addr->local_part, strcasecmp);
121 else
122 val = (gchar *) table_find_func(alias_table, addr->local_part, conf.alias_local_cmp);
124 DEBUG(5) debugf("alias: '%s' is local\n", addr->local_part);
125 if (val != NULL) {
126 GList *val_list = parse_list(val);
127 GList *val_node;
128 GList *alias_list = NULL;
130 DEBUG(5) debugf("alias: '%s' -> '%s'\n", addr->local_part, val);
131 foreach(val_list, val_node) {
132 gchar *val = (gchar *) (val_node->data);
133 address *alias_addr;
134 address *addr_parent = NULL;
136 if (val[0] == '|') {
137 DEBUG(5) debugf("alias: %s is a pipe address\n", val);
138 alias_addr = create_address_pipe(val);
139 DEBUG(5) debugf("alias_pipe: %s is a pipe address\n", alias_addr->local_part);
140 } else if (val[0] == '\\') {
141 DEBUG(5) debugf("alias: shall not be expanded: '%s'\n", val);
142 alias_addr = create_address_qualified(&(val[1]), TRUE, conf.host_name);
143 alias_addr->flags |= ADDR_FLAG_NOEXPAND;
144 DEBUG(5) debugf("alias: not expanded: '%s'\n", alias_addr->local_part);
145 } else {
146 alias_addr = create_address_qualified(val, TRUE, conf.host_name);
148 /* search in parents for loops: */
149 for (addr_parent = addr; addr_parent; addr_parent = addr_parent->parent) {
150 if (addr_isequal_alias (alias_addr, addr_parent)) {
151 logwrite(LOG_ALERT,
152 "detected alias loop, (ignoring): %s@%s -> %s@%s\n",
153 addr_parent->local_part,
154 addr_parent->domain,
155 addr->local_part, addr->domain);
156 break;
157 }
158 }
159 }
160 if (!addr_parent) {
161 alias_list = g_list_append(alias_list, alias_addr);
162 alias_addr->parent = addr;
163 }
164 g_free(val);
165 }
166 g_list_free(val_list);
167 addr->children = g_list_copy(alias_list);
168 rcpt_node = g_list_concat(rcpt_node, alias_list);
169 } else {
170 DEBUG(5) debugf("alias: '%s' is completed\n", addr->local_part);
171 done_list = g_list_append(done_list, addr);
172 }
173 } else {
174 DEBUG(5) debugf("alias: '%s@%s' is not local\n", addr->local_part, addr->domain);
175 done_list = g_list_append(done_list, addr);
176 }
177 rcpt_node = g_list_next(rcpt_node);
178 }
180 /* delete addresses from done_list if they are in the non_rcpt_list */
181 if (non_rcpt_list) {
182 GList *rcpt_node_next;
183 for (rcpt_node = g_list_first(done_list); rcpt_node; rcpt_node = rcpt_node_next) {
184 address *addr = (address *) (rcpt_node->data);
185 GList *non_node;
187 rcpt_node_next = g_list_next(rcpt_node);
189 foreach(non_rcpt_list, non_node) {
190 address *non_addr = (address *) (non_node->data);
191 if (addr_isequal(addr, non_addr)) {
192 done_list = g_list_remove_link(done_list, rcpt_node);
193 g_list_free_1(rcpt_node);
194 addr_mark_delivered(addr); /* this address is still in the children lists of the original address */
195 break;
196 }
197 }
198 }
199 }
200 return done_list;
201 }