masqmail

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