Mercurial > masqmail
view src/alias.c @ 355:ddb7b3fd3d08
found further appearences of ``localnet'' in the code
author | markus schnalke <meillo@marmaro.de> |
---|---|
date | Sun, 04 Sep 2011 11:33:31 +0200 |
parents | 273f6c9eb6a2 |
children | 41958685480d |
line wrap: on
line source
/* MasqMail Copyright (C) 2000-2001 Oliver Kurth Copyright (C) 2010 markus schnalke <meillo@marmaro.de> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "masqmail.h" #include <fnmatch.h> gboolean addr_is_local(address * addr) { GList *dom_node; GList *addr_node; address *a; if (addr->domain == NULL) { return TRUE; } foreach(conf.local_hosts, dom_node) { /* Note: FNM_CASEFOLD is a GNU extension */ if (fnmatch(dom_node->data, addr->domain, FNM_CASEFOLD) != 0) { /* no match, try next */ continue; } foreach(conf.not_local_addresses, addr_node) { a = create_address_qualified(addr_node->data, TRUE, conf.host_name); DEBUG(6) debugf("not_local_addresses: addr_node->data=%s a->address=%s\n", addr_node->data, a->address); if (addr_isequal(a, addr, conf.localpartcmp)) { destroy_address(a); /* in local_hosts but also in not_local_addresses */ return FALSE; } destroy_address(a); } /* in local_hosts */ return TRUE; } foreach(conf.local_addresses, addr_node) { a = create_address_qualified(addr_node->data, TRUE, conf.host_name); DEBUG(6) debugf("local_addresses: addr_node->data=%s a->address=%s\n", addr_node->data, a->address); if (addr_isequal(a, addr, conf.localpartcmp)) { destroy_address(a); /* in local_addresses */ return TRUE; } destroy_address(a); } return FALSE; } static GList* parse_list(gchar * line) { GList *list = NULL; gchar buf[256]; gchar *p, *q; p = line; while (*p != '\0') { q = buf; while (isspace(*p)) p++; if (*p != '"') { while (*p && (*p != ',') && (q < buf + 255)) *(q++) = *(p++); *q = '\0'; } else { gboolean escape = FALSE; p++; while (*p && (*p != '"' || escape) && (q < buf + 255)) { if ((*p == '\\') && !escape) escape = TRUE; else { escape = FALSE; *(q++) = *p; } p++; } *q = '\0'; while (*p && (*p != ',')) p++; } list = g_list_append(list, g_strdup(g_strchomp(buf))); if (*p) p++; } return list; } /* addr is assumed to be local and no pipe address nor not-to-expand */ static GList* expand_one(GList* alias_table, address* addr) { GList *val_list; GList *val_node; GList *alias_list = NULL; GList *alias_node; gchar *val; address* alias_addr; /* expand the local alias */ DEBUG(6) debugf("alias: '%s' is local and will get expanded\n", addr->local_part); if (strcasecmp(addr->local_part, "postmaster") == 0) { /* postmaster must always be matched caseless see RFC 822 and RFC 5321 */ val = (gchar *) table_find_func(alias_table, addr->local_part, strcasecmp); } else { val = (gchar *) table_find_func(alias_table, addr->local_part, conf.localpartcmp); } if (!val) { DEBUG(5) debugf("alias: '%s' is fully expanded, hence completed\n", addr->local_part); return g_list_append(NULL, addr); } DEBUG(5) debugf("alias: '%s' -> '%s'\n", addr->local_part, val); val_list = parse_list(val); alias_list = NULL; foreach(val_list, val_node) { gchar *val = (gchar *) (val_node->data); address *alias_addr; address *addr_parent = NULL; DEBUG(6) debugf("alias: processing '%s'\n", val); if (val[0] == '\\') { DEBUG(5) debugf("alias: '%s' is marked as final, hence completed\n", val); alias_addr = create_address_qualified(val+1, TRUE, conf.host_name); g_free(val); DEBUG(6) debugf("alias: address generated: '%s'\n", alias_addr->local_part); alias_list = g_list_append(alias_list, alias_addr); continue; } if (val[0] == '|') { DEBUG(5) debugf("alias: '%s' is a pipe address\n", val); alias_addr = create_address_pipe(val); g_free(val); DEBUG(6) debugf("alias: pipe generated: %s\n", alias_addr->local_part); alias_list = g_list_append(alias_list, alias_addr); continue; } alias_addr = create_address_qualified(val, TRUE, conf.host_name); g_free(val); if (!addr_is_local(alias_addr)) { DEBUG(5) debugf("alias: '%s@%s' is non-local, hence completed\n", alias_addr->local_part, alias_addr->domain); alias_list = g_list_append(alias_list, alias_addr); continue; } /* addr is local and to expand at this point */ /* but first ... search in parents for loops: */ if (addr_isequal_parent(addr, alias_addr, conf.localpartcmp)) { /* loop detected, ignore this path */ logwrite(LOG_ALERT, "alias: detected loop, hence ignoring '%s'\n", alias_addr->local_part); continue; } alias_addr->parent = addr; /* recurse */ DEBUG(6) debugf("alias: >>\n"); alias_node = expand_one(alias_table, alias_addr); DEBUG(6) debugf("alias: <<\n"); if (alias_node) { alias_list = g_list_concat(alias_list, alias_node); } } g_list_free(val_list); addr->children = g_list_copy(alias_list); return alias_list; } GList* alias_expand(GList* alias_table, GList* rcpt_list, GList* non_rcpt_list) { GList *rcpt_node = NULL; GList *alias_list = NULL; GList *done_list = NULL; GList *rcpt_node_next = NULL; address *addr = NULL; for (rcpt_node=g_list_copy(rcpt_list); rcpt_node; rcpt_node=g_list_next(rcpt_node)) { addr = (address *) (rcpt_node->data); if (addr_is_local(addr)) { DEBUG(5) debugf("alias: (orig rcpt addr) expand local '%s'\n", addr->local_part); alias_list = expand_one(alias_table, addr); if (alias_list) { done_list = g_list_concat(done_list, alias_list); } } else { DEBUG(5) debugf("alias: (orig rcpt addr) don't expand non-local '%s@%s'\n", addr->local_part, addr->domain); done_list = g_list_append(done_list, addr); } } /* we're done if we don't have to remove rcpts */ if (!non_rcpt_list) { return done_list; } /* delete addresses of non_rcpt_list from done_list */ for (rcpt_node = g_list_first(done_list); rcpt_node; rcpt_node = rcpt_node_next) { address *addr = (address *) (rcpt_node->data); GList *non_node; rcpt_node_next = g_list_next(rcpt_node); foreach(non_rcpt_list, non_node) { address *non_addr = (address *) (non_node->data); if (addr_isequal(addr, non_addr, conf.localpartcmp)) { done_list = g_list_remove_link(done_list, rcpt_node); g_list_free_1(rcpt_node); /* this address is still in the children lists of the original address, simply mark them delivered */ addr_mark_delivered(addr); break; } } } return done_list; }