masqmail

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