masqmail-0.2

view src/alias.c @ 179:ec3fe72a3e99

Fixed an important bug with folded headers! g_strconcat() returns a *copy* of the string, but hdr->value still pointed to the old header (which probably was a memory leak, too). If the folded part had been quite small it was likely that the new string was at the same position as the old one, thus making everything go well. But if pretty long headers were folded several times it was likely that the new string was allocated somewhere else in memory, thus breaking things. In result mails to lots of recipients (folded header) were frequently only sent to the ones in the first line. Sorry for the inconvenience.
author meillo@marmaro.de
date Fri, 03 Jun 2011 09:52:17 +0200
parents a8f3424347dc
children
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 }