masqmail-0.2
diff src/route.c @ 0:08114f7dcc23
this is masqmail-0.2.21 from oliver kurth
author | meillo@marmaro.de |
---|---|
date | Fri, 26 Sep 2008 17:05:23 +0200 |
parents | |
children | 26e34ae9a3e3 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/route.c Fri Sep 26 17:05:23 2008 +0200 1.3 @@ -0,0 +1,436 @@ 1.4 +/* MasqMail 1.5 + Copyright (C) 1999-2001 Oliver Kurth 1.6 + 1.7 + This program is free software; you can redistribute it and/or modify 1.8 + it under the terms of the GNU General Public License as published by 1.9 + the Free Software Foundation; either version 2 of the License, or 1.10 + (at your option) any later version. 1.11 + 1.12 + This program is distributed in the hope that it will be useful, 1.13 + but WITHOUT ANY WARRANTY; without even the implied warranty of 1.14 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.15 + GNU General Public License for more details. 1.16 + 1.17 + You should have received a copy of the GNU General Public License 1.18 + along with this program; if not, write to the Free Software 1.19 + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 1.20 +*/ 1.21 + 1.22 +#include "masqmail.h" 1.23 +#include <fnmatch.h> 1.24 + 1.25 +msgout_perhost *create_msgout_perhost(gchar *host) 1.26 +{ 1.27 + msgout_perhost *mo_ph = g_malloc(sizeof(msgout_perhost)); 1.28 + if(mo_ph){ 1.29 + mo_ph->host = g_strdup(host); 1.30 + mo_ph->msgout_list = NULL; 1.31 + } 1.32 + return mo_ph; 1.33 +} 1.34 + 1.35 +void destroy_msgout_perhost(msgout_perhost *mo_ph) 1.36 +{ 1.37 + GList *mo_node; 1.38 + 1.39 + foreach(mo_ph->msgout_list, mo_node){ 1.40 + msg_out *mo = (msg_out *)(mo_node->data); 1.41 + /* the rcpt_list is owned by the msgout's, 1.42 + but not the rcpt's themselves */ 1.43 + g_list_free(mo->rcpt_list); 1.44 + g_free(mo); 1.45 + } 1.46 + g_list_free(mo_ph->msgout_list); 1.47 + g_free(mo_ph); 1.48 +} 1.49 + 1.50 +void rewrite_headers(msg_out *msgout, connect_route *route) 1.51 +{ 1.52 + /* if set_h_from_domain is set, replace domain in all 1.53 + From: headers. 1.54 + */ 1.55 + msgout->hdr_list = g_list_copy(msgout->msg->hdr_list); 1.56 + 1.57 + /* map from addresses */ 1.58 + if(route->map_h_from_addresses != NULL){ 1.59 + GList *hdr_node; 1.60 + foreach(msgout->hdr_list, hdr_node){ 1.61 + header *hdr = (header *)(hdr_node->data); 1.62 + if(hdr->id == HEAD_FROM){ 1.63 + header *new_hdr = copy_header(hdr); 1.64 + if(map_address_header(new_hdr, route->map_h_from_addresses)){ 1.65 + hdr_node->data = new_hdr; 1.66 + /* we need this list only to carefully free the extra headers: */ 1.67 + msgout->xtra_hdr_list = 1.68 + g_list_append(msgout->xtra_hdr_list, new_hdr); 1.69 + }else 1.70 + g_free(new_hdr); 1.71 + } 1.72 + } 1.73 + }else{ 1.74 + /* replace from domain */ 1.75 + if(route->set_h_from_domain != NULL){ 1.76 + GList *hdr_node; 1.77 + 1.78 + foreach(msgout->hdr_list, hdr_node){ 1.79 + header *hdr = (header *)(hdr_node->data); 1.80 + if(hdr->id == HEAD_FROM){ 1.81 + header *new_hdr = copy_header(hdr); 1.82 + 1.83 + DEBUG(5) debugf("setting From: domain to %s\n", 1.84 + route->set_h_from_domain); 1.85 + if(set_address_header_domain(new_hdr, route->set_h_from_domain)){ 1.86 + hdr_node->data = new_hdr; 1.87 + /* we need this list only to carefully free the extra headers: */ 1.88 + DEBUG(6) debugf("header = %s\n", 1.89 + new_hdr->header); 1.90 + msgout->xtra_hdr_list = g_list_append(msgout->xtra_hdr_list, new_hdr); 1.91 + }else{ 1.92 + logwrite(LOG_ALERT, "error in set_address_header_domain(%s, %s)\n", 1.93 + new_hdr->value, route->set_h_from_domain); 1.94 + } 1.95 + } 1.96 + } 1.97 + } 1.98 + } 1.99 + 1.100 + /* map reply-to addresses */ 1.101 + if(route->map_h_reply_to_addresses != NULL){ 1.102 + GList *hdr_node; 1.103 + foreach(msgout->hdr_list, hdr_node){ 1.104 + header *hdr = (header *)(hdr_node->data); 1.105 + if(hdr->id == HEAD_REPLY_TO){ 1.106 + header *new_hdr = copy_header(hdr); 1.107 + if(map_address_header(new_hdr, route->map_h_reply_to_addresses)){ 1.108 + hdr_node->data = new_hdr; 1.109 + /* we need this list only to carefully free the extra headers: */ 1.110 + msgout->xtra_hdr_list = 1.111 + g_list_append(msgout->xtra_hdr_list, new_hdr); 1.112 + }else 1.113 + g_free(new_hdr); 1.114 + } 1.115 + } 1.116 + }else{ 1.117 + /* replace Reply-to domain */ 1.118 + if(route->set_h_reply_to_domain != NULL){ 1.119 + GList *hdr_node; 1.120 + 1.121 + foreach(msgout->hdr_list, hdr_node){ 1.122 + header *hdr = (header *)(hdr_node->data); 1.123 + if(hdr->id == HEAD_REPLY_TO){ 1.124 + header *new_hdr = copy_header(hdr); 1.125 + 1.126 + set_address_header_domain(new_hdr, route->set_h_reply_to_domain); 1.127 + hdr_node->data = new_hdr; 1.128 + /* we need this list only to carefully free the extra headers: */ 1.129 + msgout->xtra_hdr_list = g_list_append(msgout->xtra_hdr_list, new_hdr); 1.130 + } 1.131 + } 1.132 + } 1.133 + } 1.134 + 1.135 + /* map Mail-Followup-To addresses */ 1.136 + if(route->map_h_mail_followup_to_addresses != NULL){ 1.137 + GList *hdr_node; 1.138 + foreach(msgout->hdr_list, hdr_node){ 1.139 + header *hdr = (header *)(hdr_node->data); 1.140 + if(strncasecmp(hdr->header, "Mail-Followup-To", 16) == 0){ 1.141 + header *new_hdr = copy_header(hdr); 1.142 + if(map_address_header(new_hdr, route->map_h_mail_followup_to_addresses)){ 1.143 + hdr_node->data = new_hdr; 1.144 + /* we need this list only to carefully free the extra headers: */ 1.145 + msgout->xtra_hdr_list = 1.146 + g_list_append(msgout->xtra_hdr_list, new_hdr); 1.147 + }else 1.148 + g_free(new_hdr); 1.149 + } 1.150 + } 1.151 + } 1.152 + 1.153 + /* set Sender: domain to return_path->domain */ 1.154 + if(route->expand_h_sender_domain){ 1.155 + GList *hdr_node; 1.156 + 1.157 + foreach(msgout->hdr_list, hdr_node){ 1.158 + header *hdr = (header *)(hdr_node->data); 1.159 + if(hdr->id == HEAD_SENDER){ 1.160 + header *new_hdr = copy_header(hdr); 1.161 + 1.162 + set_address_header_domain(new_hdr, msgout->return_path->domain); 1.163 + hdr_node->data = new_hdr; 1.164 + /* we need this list only to carefully free the extra headers: */ 1.165 + msgout->xtra_hdr_list = g_list_append(msgout->xtra_hdr_list, new_hdr); 1.166 + } 1.167 + } 1.168 + } 1.169 + 1.170 + /* set Sender: domain to return_path->domain */ 1.171 + if(route->expand_h_sender_address){ 1.172 + GList *hdr_node; 1.173 + 1.174 + foreach(msgout->hdr_list, hdr_node){ 1.175 + header *hdr = (header *)(hdr_node->data); 1.176 + if(hdr->id == HEAD_SENDER){ 1.177 + header *new_hdr; 1.178 + 1.179 + new_hdr = 1.180 + create_header(HEAD_SENDER, "Sender: %s@%s\n", 1.181 + msgout->return_path->local_part, msgout->return_path->domain); 1.182 + hdr_node->data = new_hdr; 1.183 + /* we need this list only to carefully free the extra headers: */ 1.184 + msgout->xtra_hdr_list = g_list_append(msgout->xtra_hdr_list, new_hdr); 1.185 + } 1.186 + } 1.187 + } 1.188 + 1.189 + if(msgout->xtra_hdr_list == NULL){ 1.190 + /* nothing was changed */ 1.191 + g_list_free(msgout->hdr_list); 1.192 + msgout->hdr_list = NULL; 1.193 + } 1.194 + DEBUG(5) debugf("rewrite_headers() returning\n"); 1.195 +} 1.196 + 1.197 +void rcptlist_with_one_of_hostlist(GList *rcpt_list, GList *host_list, 1.198 + GList **p_rcpt_list, GList **p_non_rcpt_list) 1.199 +{ 1.200 + GList *rcpt_node; 1.201 + 1.202 + if(rcpt_list == NULL) 1.203 + return; 1.204 + 1.205 + foreach(rcpt_list, rcpt_node){ 1.206 + address *rcpt = (address *)(rcpt_node->data); 1.207 + GList *host_node = NULL; 1.208 + 1.209 + foreach(host_list, host_node){ 1.210 + gchar *host = (gchar *)(host_node->data); 1.211 + if(fnmatch(host, rcpt->domain, FNM_CASEFOLD) == 0) 1.212 + break; 1.213 + } 1.214 + if(host_node){ 1.215 + if(p_rcpt_list) 1.216 + *p_rcpt_list = g_list_append(*p_rcpt_list, rcpt); 1.217 + }else{ 1.218 + if(p_non_rcpt_list) 1.219 + *p_non_rcpt_list = g_list_append(*p_non_rcpt_list, rcpt); 1.220 + } 1.221 + 1.222 + } 1.223 +} 1.224 + 1.225 +void rcptlist_with_addr_is_local(GList *rcpt_list, 1.226 + GList **p_rcpt_list, GList **p_non_rcpt_list) 1.227 +{ 1.228 + GList *rcpt_node; 1.229 + 1.230 + if(rcpt_list == NULL) 1.231 + return; 1.232 + 1.233 + foreach(rcpt_list, rcpt_node){ 1.234 + address *rcpt = (address *)(rcpt_node->data); 1.235 + if(addr_is_local(rcpt)){ 1.236 + if(p_rcpt_list) 1.237 + *p_rcpt_list = g_list_append(*p_rcpt_list, rcpt); 1.238 + }else{ 1.239 + if(p_non_rcpt_list) 1.240 + *p_non_rcpt_list = g_list_append(*p_non_rcpt_list, rcpt); 1.241 + } 1.242 + 1.243 + } 1.244 +} 1.245 + 1.246 +static gint _g_list_addrcmp(gconstpointer a, gconstpointer b) 1.247 +{ 1.248 + return addr_match((address *)a, (address *)b); 1.249 +} 1.250 + 1.251 +gboolean route_is_allowed_return_path(connect_route *route, address *ret_path) 1.252 +{ 1.253 + if(route->not_allowed_return_paths != NULL){ 1.254 + if(g_list_find_custom(route->not_allowed_return_paths, ret_path, 1.255 + _g_list_addrcmp) != NULL){ 1.256 + return FALSE; 1.257 + } 1.258 + } 1.259 + if(route->allowed_return_paths != NULL){ 1.260 + if(g_list_find_custom(route->allowed_return_paths, ret_path, 1.261 + _g_list_addrcmp) != NULL){ 1.262 + return TRUE; 1.263 + }else{ 1.264 + return FALSE; 1.265 + } 1.266 + } 1.267 + return TRUE; 1.268 +} 1.269 + 1.270 +static gint _g_list_strcmp(gconstpointer a, gconstpointer b) 1.271 +{ 1.272 + return (gint)strcmp(a, b); 1.273 +} 1.274 + 1.275 +gboolean route_is_allowed_mail_local(connect_route *route, address *ret_path) 1.276 +{ 1.277 + gchar *loc_part = ret_path->local_part; 1.278 + 1.279 + if(route->not_allowed_mail_locals != NULL){ 1.280 + if(g_list_find_custom(route->not_allowed_mail_locals, loc_part, 1.281 + _g_list_strcmp) != NULL) 1.282 + return FALSE; 1.283 + } 1.284 + if(route->allowed_mail_locals != NULL){ 1.285 + if(g_list_find_custom(route->allowed_mail_locals, loc_part, 1.286 + _g_list_strcmp) != NULL) 1.287 + return TRUE; 1.288 + else 1.289 + return FALSE; 1.290 + } 1.291 + return TRUE; 1.292 +} 1.293 + 1.294 +/* 1.295 + Make lists of matching/not matching rcpts. 1.296 + Local domains are NOT regared here, these should be sorted out previously 1.297 +*/ 1.298 +void msg_rcptlist_route(connect_route *route, GList *rcpt_list, 1.299 + GList **p_rcpt_list, GList **p_non_rcpt_list) 1.300 +{ 1.301 + GList *tmp_list = NULL; 1.302 + /* sort out those domains that can be sent over this connection: */ 1.303 + if(route->allowed_rcpt_domains){ 1.304 + DEBUG(5) debugf("testing for route->allowed_rcpt_domains\n"); 1.305 + rcptlist_with_one_of_hostlist(rcpt_list, route->allowed_rcpt_domains, &tmp_list, p_non_rcpt_list); 1.306 + }else{ 1.307 + DEBUG(5) debugf("route->allowed_rcpt_domains == NULL\n"); 1.308 + tmp_list = g_list_copy(rcpt_list); 1.309 + } 1.310 + 1.311 + /* sort out those domains that cannot be sent over this connection: */ 1.312 + rcptlist_with_one_of_hostlist(tmp_list, route->not_allowed_rcpt_domains, p_non_rcpt_list, p_rcpt_list); 1.313 + g_list_free(tmp_list); 1.314 +} 1.315 + 1.316 +msg_out *route_prepare_msgout(connect_route *route, msg_out *msgout) 1.317 +{ 1.318 + message *msg = msgout->msg; 1.319 + GList *rcpt_list = msgout->rcpt_list; 1.320 + 1.321 + if(rcpt_list != NULL){ 1.322 + /* found a few */ 1.323 + DEBUG(5){ 1.324 + GList *node; 1.325 + debugf("rcpts for routed delivery, route = %s, id = %s\n", route->name, msg->uid); 1.326 + foreach(rcpt_list, node){ 1.327 + address *rcpt = (address *)(node->data); 1.328 + debugf("rcpt for routed delivery: <%s@%s>\n", 1.329 + rcpt->local_part, rcpt->domain); 1.330 + } 1.331 + } 1.332 + 1.333 + /* rewrite return path 1.334 + if there is a table, use that 1.335 + if an address is found and if it has a domain, use that 1.336 + */ 1.337 + if(route->map_return_path_addresses){ 1.338 + address *ret_path = NULL; 1.339 + DEBUG(5) debugf("looking up %s in map_return_path_addresses\n", 1.340 + msg->return_path->local_part); 1.341 + ret_path = 1.342 + (address *)table_find_fnmatch(route->map_return_path_addresses, 1.343 + msg->return_path->local_part); 1.344 + if(ret_path){ 1.345 + DEBUG(5) debugf("found <%s@%s>\n", 1.346 + ret_path->local_part, ret_path->domain); 1.347 + if(ret_path->domain == NULL) 1.348 + ret_path->domain = 1.349 + route->set_return_path_domain ? 1.350 + route->set_return_path_domain : msg->return_path->domain; 1.351 + msgout->return_path = copy_address(ret_path); 1.352 + } 1.353 + } 1.354 + if(msgout->return_path == NULL){ 1.355 + DEBUG(5) debugf("setting return path to %s\n", 1.356 + route->set_return_path_domain); 1.357 + msgout->return_path = 1.358 + copy_modify_address(msg->return_path, 1.359 + NULL, route->set_return_path_domain); 1.360 + } 1.361 + rewrite_headers(msgout, route); 1.362 + 1.363 + return msgout; 1.364 + } 1.365 + return NULL; 1.366 +} 1.367 + 1.368 +/* put msgout's is msgout_list into bins (msgout_perhost structs) for each 1.369 + host. Used if there is no mail_host. 1.370 + route param is not used, we leave it here because that may change. 1.371 + */ 1.372 + 1.373 +GList *route_msgout_list(connect_route *route, GList *msgout_list) 1.374 +{ 1.375 + GList *mo_ph_list = NULL; 1.376 + GList *msgout_node; 1.377 + 1.378 + foreach(msgout_list, msgout_node){ 1.379 + msg_out *msgout = (msg_out *)(msgout_node->data); 1.380 + msg_out *msgout_new; 1.381 + GList *rcpt_list = msgout->rcpt_list; 1.382 + GList *rcpt_node; 1.383 + 1.384 + foreach(rcpt_list, rcpt_node){ 1.385 + address *rcpt = rcpt_node->data; 1.386 + msgout_perhost *mo_ph = NULL; 1.387 + GList *mo_ph_node = NULL; 1.388 + 1.389 + /* search host in mo_ph_list */ 1.390 + foreach(mo_ph_list, mo_ph_node){ 1.391 + mo_ph = (msgout_perhost *)(mo_ph_node->data); 1.392 + if(strcasecmp(mo_ph->host, rcpt->domain) == 0) 1.393 + break; 1.394 + } 1.395 + if(mo_ph_node != NULL){ 1.396 + /* there is already a rcpt for this host */ 1.397 + msg_out *msgout_last = 1.398 + (msg_out *)((g_list_last(mo_ph->msgout_list))->data); 1.399 + if(msgout_last->msg == msgout->msg){ 1.400 + /* if it is also the same message, it must be the last one 1.401 + appended to mo_ph->msgout_list (since outer loop goes through 1.402 + msgout_list) */ 1.403 + msgout_last->rcpt_list = 1.404 + g_list_append(msgout_last->rcpt_list, rcpt); 1.405 + }else{ 1.406 + /* if not, we append a new msgout */ 1.407 + /* make a copy of msgout */ 1.408 + msgout_new = create_msg_out(msgout->msg); 1.409 + msgout_new->return_path = msgout->return_path; 1.410 + msgout_new->hdr_list = msgout->hdr_list; 1.411 + 1.412 + /* append our rcpt to it */ 1.413 + /* It is the 1st rcpt for this msg to this host, 1.414 + therefore we safely give NULL */ 1.415 + msgout_new->rcpt_list = g_list_append(NULL, rcpt); 1.416 + mo_ph->msgout_list = 1.417 + g_list_append(mo_ph->msgout_list, msgout_new); 1.418 + } 1.419 + }else{ 1.420 + /* this rcpt to goes to another host */ 1.421 + mo_ph = create_msgout_perhost(rcpt->domain); 1.422 + mo_ph_list = g_list_append(mo_ph_list, mo_ph); 1.423 + 1.424 + /* make a copy of msgout */ 1.425 + msgout_new = create_msg_out(msgout->msg); 1.426 + msgout_new->return_path = msgout->return_path; 1.427 + msgout_new->hdr_list = msgout->hdr_list; 1.428 + 1.429 + /* append our rcpt to it */ 1.430 + /* It is the 1st rcpt for this msg to this host, 1.431 + therefore we safely give NULL */ 1.432 + msgout_new->rcpt_list = g_list_append(NULL, rcpt); 1.433 + mo_ph->msgout_list = g_list_append(mo_ph->msgout_list, msgout_new); 1.434 + }/* if mo_ph != NULL */ 1.435 + }/* foreach(rcpt_list, ... */ 1.436 + }/* foreach(msgout_list, ... */ 1.437 + 1.438 + return mo_ph_list; 1.439 +}