masqmail

annotate src/route.c @ 91:3e7136221104

correct masqmail path in rmail script; remove docs on uninstall on install the correct path to the masqmail executable gets inserted into the rmail script now. now documentation, examples, and the templates are removed on uninstall. Empty directories are the only thing that may remain if one installs masqmail into an unusual path.
author meillo@marmaro.de
date Mon, 21 Jun 2010 09:40:16 +0200
parents 26e34ae9a3e3
children a80ebfa16cd5
rev   line source
meillo@0 1 /* MasqMail
meillo@0 2 Copyright (C) 1999-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@15 19 #include <fnmatch.h>
meillo@15 20
meillo@0 21 #include "masqmail.h"
meillo@0 22
meillo@10 23 msgout_perhost*
meillo@10 24 create_msgout_perhost(gchar * host)
meillo@0 25 {
meillo@10 26 msgout_perhost *mo_ph = g_malloc(sizeof(msgout_perhost));
meillo@10 27 if (mo_ph) {
meillo@10 28 mo_ph->host = g_strdup(host);
meillo@10 29 mo_ph->msgout_list = NULL;
meillo@10 30 }
meillo@10 31 return mo_ph;
meillo@0 32 }
meillo@0 33
meillo@10 34 void
meillo@10 35 destroy_msgout_perhost(msgout_perhost * mo_ph)
meillo@0 36 {
meillo@10 37 GList *mo_node;
meillo@0 38
meillo@10 39 foreach(mo_ph->msgout_list, mo_node) {
meillo@10 40 msg_out *mo = (msg_out *) (mo_node->data);
meillo@10 41 /* the rcpt_list is owned by the msgout's, but not the rcpt's themselves */
meillo@10 42 g_list_free(mo->rcpt_list);
meillo@10 43 g_free(mo);
meillo@10 44 }
meillo@10 45 g_list_free(mo_ph->msgout_list);
meillo@10 46 g_free(mo_ph);
meillo@0 47 }
meillo@0 48
meillo@10 49 void
meillo@10 50 rewrite_headers(msg_out * msgout, connect_route * route)
meillo@0 51 {
meillo@10 52 /* if set_h_from_domain is set, replace domain in all
meillo@10 53 From: headers.
meillo@10 54 */
meillo@10 55 msgout->hdr_list = g_list_copy(msgout->msg->hdr_list);
meillo@0 56
meillo@10 57 /* map from addresses */
meillo@10 58 if (route->map_h_from_addresses != NULL) {
meillo@10 59 GList *hdr_node;
meillo@10 60 foreach(msgout->hdr_list, hdr_node) {
meillo@10 61 header *hdr = (header *) (hdr_node->data);
meillo@10 62 if (hdr->id == HEAD_FROM) {
meillo@10 63 header *new_hdr = copy_header(hdr);
meillo@10 64 if (map_address_header(new_hdr, route->map_h_from_addresses)) {
meillo@10 65 hdr_node->data = new_hdr;
meillo@10 66 /* we need this list only to carefully free the extra headers: */
meillo@10 67 msgout->xtra_hdr_list = g_list_append(msgout->xtra_hdr_list, new_hdr);
meillo@10 68 } else
meillo@10 69 g_free(new_hdr);
meillo@10 70 }
meillo@10 71 }
meillo@10 72 } else {
meillo@10 73 /* replace from domain */
meillo@10 74 if (route->set_h_from_domain != NULL) {
meillo@10 75 GList *hdr_node;
meillo@10 76
meillo@10 77 foreach(msgout->hdr_list, hdr_node) {
meillo@10 78 header *hdr = (header *) (hdr_node->data);
meillo@10 79 if (hdr->id == HEAD_FROM) {
meillo@10 80 header *new_hdr = copy_header(hdr);
meillo@10 81
meillo@10 82 DEBUG(5) debugf("setting From: domain to %s\n", route->set_h_from_domain);
meillo@10 83 if (set_address_header_domain(new_hdr, route->set_h_from_domain)) {
meillo@10 84 hdr_node->data = new_hdr;
meillo@10 85 /* we need this list only to carefully free the extra headers: */
meillo@10 86 DEBUG(6) debugf("header = %s\n", new_hdr->header);
meillo@10 87 msgout->xtra_hdr_list = g_list_append(msgout->xtra_hdr_list, new_hdr);
meillo@10 88 } else {
meillo@15 89 logwrite(LOG_ALERT, "error in set_address_header_domain(%s, %s)\n",
meillo@15 90 new_hdr->value, route->set_h_from_domain);
meillo@10 91 }
meillo@10 92 }
meillo@10 93 }
meillo@10 94 }
meillo@0 95 }
meillo@0 96
meillo@10 97 /* map reply-to addresses */
meillo@10 98 if (route->map_h_reply_to_addresses != NULL) {
meillo@10 99 GList *hdr_node;
meillo@10 100 foreach(msgout->hdr_list, hdr_node) {
meillo@10 101 header *hdr = (header *) (hdr_node->data);
meillo@10 102 if (hdr->id == HEAD_REPLY_TO) {
meillo@10 103 header *new_hdr = copy_header(hdr);
meillo@10 104 if (map_address_header
meillo@10 105 (new_hdr, route->map_h_reply_to_addresses)) {
meillo@10 106 hdr_node->data = new_hdr;
meillo@10 107 /* we need this list only to carefully free the extra headers: */
meillo@10 108 msgout->xtra_hdr_list = g_list_append(msgout->xtra_hdr_list, new_hdr);
meillo@10 109 } else
meillo@10 110 g_free(new_hdr);
meillo@10 111 }
meillo@10 112 }
meillo@10 113 } else {
meillo@10 114 /* replace Reply-to domain */
meillo@10 115 if (route->set_h_reply_to_domain != NULL) {
meillo@10 116 GList *hdr_node;
meillo@10 117
meillo@10 118 foreach(msgout->hdr_list, hdr_node) {
meillo@10 119 header *hdr = (header *) (hdr_node->data);
meillo@10 120 if (hdr->id == HEAD_REPLY_TO) {
meillo@10 121 header *new_hdr = copy_header(hdr);
meillo@10 122
meillo@10 123 set_address_header_domain(new_hdr, route-> set_h_reply_to_domain);
meillo@10 124 hdr_node->data = new_hdr;
meillo@10 125 /* we need this list only to carefully free the extra headers: */
meillo@10 126 msgout->xtra_hdr_list = g_list_append(msgout->xtra_hdr_list, new_hdr);
meillo@10 127 }
meillo@10 128 }
meillo@10 129 }
meillo@0 130 }
meillo@0 131
meillo@10 132 /* map Mail-Followup-To addresses */
meillo@10 133 if (route->map_h_mail_followup_to_addresses != NULL) {
meillo@10 134 GList *hdr_node;
meillo@10 135 foreach(msgout->hdr_list, hdr_node) {
meillo@10 136 header *hdr = (header *) (hdr_node->data);
meillo@10 137 if (strncasecmp(hdr->header, "Mail-Followup-To", 16) == 0) {
meillo@10 138 header *new_hdr = copy_header(hdr);
meillo@10 139 if (map_address_header(new_hdr, route->map_h_mail_followup_to_addresses)) {
meillo@10 140 hdr_node->data = new_hdr;
meillo@10 141 /* we need this list only to carefully free the extra headers: */
meillo@10 142 msgout->xtra_hdr_list = g_list_append(msgout->xtra_hdr_list, new_hdr);
meillo@10 143 } else
meillo@10 144 g_free(new_hdr);
meillo@10 145 }
meillo@10 146 }
meillo@10 147 }
meillo@0 148
meillo@10 149 /* set Sender: domain to return_path->domain */
meillo@10 150 if (route->expand_h_sender_domain) {
meillo@10 151 GList *hdr_node;
meillo@0 152
meillo@10 153 foreach(msgout->hdr_list, hdr_node) {
meillo@10 154 header *hdr = (header *) (hdr_node->data);
meillo@10 155 if (hdr->id == HEAD_SENDER) {
meillo@10 156 header *new_hdr = copy_header(hdr);
meillo@0 157
meillo@10 158 set_address_header_domain(new_hdr, msgout->return_path->domain);
meillo@10 159 hdr_node->data = new_hdr;
meillo@10 160 /* we need this list only to carefully free the extra headers: */
meillo@10 161 msgout->xtra_hdr_list = g_list_append(msgout->xtra_hdr_list, new_hdr);
meillo@10 162 }
meillo@10 163 }
meillo@10 164 }
meillo@0 165
meillo@10 166 /* set Sender: domain to return_path->domain */
meillo@10 167 if (route->expand_h_sender_address) {
meillo@10 168 GList *hdr_node;
meillo@0 169
meillo@10 170 foreach(msgout->hdr_list, hdr_node) {
meillo@10 171 header *hdr = (header *) (hdr_node->data);
meillo@10 172 if (hdr->id == HEAD_SENDER) {
meillo@10 173 header *new_hdr;
meillo@0 174
meillo@15 175 new_hdr = create_header(HEAD_SENDER, "Sender: %s@%s\n",
meillo@15 176 msgout->return_path->local_part, msgout->return_path->domain);
meillo@10 177 hdr_node->data = new_hdr;
meillo@10 178 /* we need this list only to carefully free the extra headers: */
meillo@10 179 msgout->xtra_hdr_list = g_list_append(msgout->xtra_hdr_list, new_hdr);
meillo@10 180 }
meillo@10 181 }
meillo@10 182 }
meillo@0 183
meillo@10 184 if (msgout->xtra_hdr_list == NULL) {
meillo@10 185 /* nothing was changed */
meillo@10 186 g_list_free(msgout->hdr_list);
meillo@10 187 msgout->hdr_list = NULL;
meillo@10 188 }
meillo@10 189 DEBUG(5) debugf("rewrite_headers() returning\n");
meillo@0 190 }
meillo@0 191
meillo@10 192 void
meillo@10 193 rcptlist_with_one_of_hostlist(GList * rcpt_list, GList * host_list, GList ** p_rcpt_list, GList ** p_non_rcpt_list)
meillo@0 194 {
meillo@10 195 GList *rcpt_node;
meillo@0 196
meillo@10 197 if (rcpt_list == NULL)
meillo@10 198 return;
meillo@0 199
meillo@10 200 foreach(rcpt_list, rcpt_node) {
meillo@10 201 address *rcpt = (address *) (rcpt_node->data);
meillo@10 202 GList *host_node = NULL;
meillo@0 203
meillo@10 204 foreach(host_list, host_node) {
meillo@10 205 gchar *host = (gchar *) (host_node->data);
meillo@10 206 if (fnmatch(host, rcpt->domain, FNM_CASEFOLD) == 0)
meillo@10 207 break;
meillo@10 208 }
meillo@10 209 if (host_node) {
meillo@10 210 if (p_rcpt_list)
meillo@10 211 *p_rcpt_list = g_list_append(*p_rcpt_list, rcpt);
meillo@10 212 } else {
meillo@10 213 if (p_non_rcpt_list)
meillo@10 214 *p_non_rcpt_list = g_list_append(*p_non_rcpt_list, rcpt);
meillo@10 215 }
meillo@0 216
meillo@10 217 }
meillo@0 218 }
meillo@0 219
meillo@10 220 void
meillo@10 221 rcptlist_with_addr_is_local(GList * rcpt_list, GList ** p_rcpt_list, GList ** p_non_rcpt_list)
meillo@0 222 {
meillo@10 223 GList *rcpt_node;
meillo@0 224
meillo@10 225 if (rcpt_list == NULL)
meillo@10 226 return;
meillo@0 227
meillo@10 228 foreach(rcpt_list, rcpt_node) {
meillo@10 229 address *rcpt = (address *) (rcpt_node->data);
meillo@10 230 if (addr_is_local(rcpt)) {
meillo@10 231 if (p_rcpt_list)
meillo@10 232 *p_rcpt_list = g_list_append(*p_rcpt_list, rcpt);
meillo@10 233 } else {
meillo@10 234 if (p_non_rcpt_list)
meillo@10 235 *p_non_rcpt_list = g_list_append(*p_non_rcpt_list, rcpt);
meillo@10 236 }
meillo@0 237
meillo@10 238 }
meillo@0 239 }
meillo@0 240
meillo@10 241 static gint
meillo@10 242 _g_list_addrcmp(gconstpointer a, gconstpointer b)
meillo@0 243 {
meillo@10 244 return addr_match((address *) a, (address *) b);
meillo@0 245 }
meillo@0 246
meillo@10 247 gboolean
meillo@10 248 route_is_allowed_return_path(connect_route * route, address * ret_path)
meillo@0 249 {
meillo@10 250 if (route->not_allowed_return_paths != NULL) {
meillo@10 251 if (g_list_find_custom(route->not_allowed_return_paths, ret_path, _g_list_addrcmp) != NULL) {
meillo@10 252 return FALSE;
meillo@10 253 }
meillo@10 254 }
meillo@10 255 if (route->allowed_return_paths != NULL) {
meillo@10 256 if (g_list_find_custom(route->allowed_return_paths, ret_path, _g_list_addrcmp) != NULL) {
meillo@10 257 return TRUE;
meillo@10 258 } else {
meillo@10 259 return FALSE;
meillo@10 260 }
meillo@10 261 }
meillo@10 262 return TRUE;
meillo@0 263 }
meillo@0 264
meillo@10 265 static gint
meillo@10 266 _g_list_strcmp(gconstpointer a, gconstpointer b)
meillo@0 267 {
meillo@10 268 return (gint) strcmp(a, b);
meillo@0 269 }
meillo@0 270
meillo@10 271 gboolean
meillo@10 272 route_is_allowed_mail_local(connect_route * route, address * ret_path)
meillo@0 273 {
meillo@10 274 gchar *loc_part = ret_path->local_part;
meillo@0 275
meillo@10 276 if (route->not_allowed_mail_locals != NULL) {
meillo@10 277 if (g_list_find_custom(route->not_allowed_mail_locals, loc_part, _g_list_strcmp) != NULL)
meillo@10 278 return FALSE;
meillo@10 279 }
meillo@10 280 if (route->allowed_mail_locals != NULL) {
meillo@10 281 if (g_list_find_custom(route->allowed_mail_locals, loc_part, _g_list_strcmp) != NULL)
meillo@10 282 return TRUE;
meillo@10 283 else
meillo@10 284 return FALSE;
meillo@10 285 }
meillo@10 286 return TRUE;
meillo@0 287 }
meillo@0 288
meillo@10 289 /*
meillo@0 290 Make lists of matching/not matching rcpts.
meillo@0 291 Local domains are NOT regared here, these should be sorted out previously
meillo@0 292 */
meillo@10 293 void
meillo@10 294 msg_rcptlist_route(connect_route * route, GList * rcpt_list, GList ** p_rcpt_list, GList ** p_non_rcpt_list)
meillo@0 295 {
meillo@10 296 GList *tmp_list = NULL;
meillo@10 297 /* sort out those domains that can be sent over this connection: */
meillo@10 298 if (route->allowed_rcpt_domains) {
meillo@10 299 DEBUG(5) debugf("testing for route->allowed_rcpt_domains\n");
meillo@10 300 rcptlist_with_one_of_hostlist(rcpt_list, route->allowed_rcpt_domains, &tmp_list, p_non_rcpt_list);
meillo@10 301 } else {
meillo@10 302 DEBUG(5) debugf("route->allowed_rcpt_domains == NULL\n");
meillo@10 303 tmp_list = g_list_copy(rcpt_list);
meillo@10 304 }
meillo@0 305
meillo@10 306 /* sort out those domains that cannot be sent over this connection: */
meillo@10 307 rcptlist_with_one_of_hostlist(tmp_list, route->not_allowed_rcpt_domains, p_non_rcpt_list, p_rcpt_list);
meillo@10 308 g_list_free(tmp_list);
meillo@0 309 }
meillo@0 310
meillo@10 311 msg_out*
meillo@10 312 route_prepare_msgout(connect_route * route, msg_out * msgout)
meillo@0 313 {
meillo@10 314 message *msg = msgout->msg;
meillo@10 315 GList *rcpt_list = msgout->rcpt_list;
meillo@0 316
meillo@10 317 if (rcpt_list != NULL) {
meillo@10 318 /* found a few */
meillo@10 319 DEBUG(5) {
meillo@10 320 GList *node;
meillo@10 321 debugf("rcpts for routed delivery, route = %s, id = %s\n", route->name, msg->uid);
meillo@10 322 foreach(rcpt_list, node) {
meillo@10 323 address *rcpt = (address *) (node->data);
meillo@10 324 debugf("rcpt for routed delivery: <%s@%s>\n", rcpt->local_part, rcpt->domain);
meillo@10 325 }
meillo@10 326 }
meillo@0 327
meillo@15 328 /* rewrite return path if there is a table, use that
meillo@10 329 if an address is found and if it has a domain, use that
meillo@10 330 */
meillo@10 331 if (route->map_return_path_addresses) {
meillo@10 332 address *ret_path = NULL;
meillo@10 333 DEBUG(5) debugf("looking up %s in map_return_path_addresses\n", msg->return_path->local_part);
meillo@10 334 ret_path = (address *) table_find_fnmatch(route->map_return_path_addresses, msg->return_path->local_part);
meillo@10 335 if (ret_path) {
meillo@10 336 DEBUG(5) debugf("found <%s@%s>\n", ret_path->local_part, ret_path->domain);
meillo@10 337 if (ret_path->domain == NULL)
meillo@10 338 ret_path->domain = route->set_return_path_domain
meillo@10 339 ? route->set_return_path_domain
meillo@10 340 : msg->return_path->domain;
meillo@10 341 msgout->return_path = copy_address(ret_path);
meillo@10 342 }
meillo@10 343 }
meillo@10 344 if (msgout->return_path == NULL) {
meillo@10 345 DEBUG(5) debugf("setting return path to %s\n", route->set_return_path_domain);
meillo@10 346 msgout->return_path = copy_modify_address(msg->return_path, NULL, route->set_return_path_domain);
meillo@10 347 }
meillo@10 348 rewrite_headers(msgout, route);
meillo@10 349
meillo@10 350 return msgout;
meillo@10 351 }
meillo@10 352 return NULL;
meillo@0 353 }
meillo@0 354
meillo@0 355 /* put msgout's is msgout_list into bins (msgout_perhost structs) for each
meillo@0 356 host. Used if there is no mail_host.
meillo@0 357 route param is not used, we leave it here because that may change.
meillo@0 358 */
meillo@0 359
meillo@10 360 GList*
meillo@10 361 route_msgout_list(connect_route * route, GList * msgout_list)
meillo@0 362 {
meillo@10 363 GList *mo_ph_list = NULL;
meillo@10 364 GList *msgout_node;
meillo@0 365
meillo@10 366 foreach(msgout_list, msgout_node) {
meillo@10 367 msg_out *msgout = (msg_out *) (msgout_node->data);
meillo@10 368 msg_out *msgout_new;
meillo@10 369 GList *rcpt_list = msgout->rcpt_list;
meillo@10 370 GList *rcpt_node;
meillo@0 371
meillo@10 372 foreach(rcpt_list, rcpt_node) {
meillo@10 373 address *rcpt = rcpt_node->data;
meillo@10 374 msgout_perhost *mo_ph = NULL;
meillo@10 375 GList *mo_ph_node = NULL;
meillo@0 376
meillo@10 377 /* search host in mo_ph_list */
meillo@10 378 foreach(mo_ph_list, mo_ph_node) {
meillo@10 379 mo_ph = (msgout_perhost *) (mo_ph_node->data);
meillo@10 380 if (strcasecmp(mo_ph->host, rcpt->domain) == 0)
meillo@10 381 break;
meillo@10 382 }
meillo@10 383 if (mo_ph_node != NULL) {
meillo@10 384 /* there is already a rcpt for this host */
meillo@10 385 msg_out *msgout_last = (msg_out *) ((g_list_last(mo_ph->msgout_list))->data);
meillo@10 386 if (msgout_last->msg == msgout->msg) {
meillo@15 387 /* if it is also the same message, it must be the last one appended
meillo@15 388 to mo_ph->msgout_list (since outer loop goes through msgout_list) */
meillo@10 389 msgout_last->rcpt_list = g_list_append(msgout_last->rcpt_list, rcpt);
meillo@10 390 } else {
meillo@10 391 /* if not, we append a new msgout */
meillo@10 392 /* make a copy of msgout */
meillo@10 393 msgout_new = create_msg_out(msgout->msg);
meillo@10 394 msgout_new->return_path = msgout->return_path;
meillo@10 395 msgout_new->hdr_list = msgout->hdr_list;
meillo@0 396
meillo@10 397 /* append our rcpt to it */
meillo@10 398 /* It is the 1st rcpt for this msg to this host, therefore we safely give NULL */
meillo@10 399 msgout_new->rcpt_list = g_list_append(NULL, rcpt);
meillo@10 400 mo_ph->msgout_list = g_list_append(mo_ph->msgout_list, msgout_new);
meillo@10 401 }
meillo@10 402 } else {
meillo@10 403 /* this rcpt to goes to another host */
meillo@10 404 mo_ph = create_msgout_perhost(rcpt->domain);
meillo@10 405 mo_ph_list = g_list_append(mo_ph_list, mo_ph);
meillo@0 406
meillo@10 407 /* make a copy of msgout */
meillo@10 408 msgout_new = create_msg_out(msgout->msg);
meillo@10 409 msgout_new->return_path = msgout->return_path;
meillo@10 410 msgout_new->hdr_list = msgout->hdr_list;
meillo@0 411
meillo@10 412 /* append our rcpt to it */
meillo@10 413 /* It is the 1st rcpt for this msg to this host, therefore we safely give NULL */
meillo@10 414 msgout_new->rcpt_list = g_list_append(NULL, rcpt);
meillo@10 415 mo_ph->msgout_list = g_list_append(mo_ph->msgout_list, msgout_new);
meillo@10 416 } /* if mo_ph != NULL */
meillo@10 417 } /* foreach(rcpt_list, ... */
meillo@10 418 } /* foreach(msgout_list, ... */
meillo@10 419
meillo@10 420 return mo_ph_list;
meillo@0 421 }