masqmail

annotate src/fail_msg.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 41958685480d
children 8518fe2b0f36
rev   line source
meillo@367 1 /*
meillo@367 2 ** MasqMail
meillo@367 3 ** Copyright (C) 2000-2001 Oliver Kurth
meillo@367 4 **
meillo@367 5 ** This program is free software; you can redistribute it and/or modify
meillo@367 6 ** it under the terms of the GNU General Public License as published by
meillo@367 7 ** the Free Software Foundation; either version 2 of the License, or
meillo@367 8 ** (at your option) any later version.
meillo@367 9 **
meillo@367 10 ** This program is distributed in the hope that it will be useful,
meillo@367 11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
meillo@367 12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
meillo@367 13 ** GNU General Public License for more details.
meillo@367 14 **
meillo@367 15 ** You should have received a copy of the GNU General Public License
meillo@367 16 ** along with this program; if not, write to the Free Software
meillo@367 17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
meillo@367 18 */
meillo@0 19
meillo@0 20 #include <sys/wait.h>
meillo@0 21
meillo@0 22 #include "masqmail.h"
meillo@0 23 #include "peopen.h"
meillo@0 24 #include "readsock.h"
meillo@0 25
meillo@10 26 gboolean
meillo@367 27 fail_msg(message *msg, gchar *template, GList *failed_rcpts, gchar *err_fmt,
meillo@367 28 va_list args)
meillo@0 29 {
meillo@10 30 gboolean ok = FALSE;
meillo@10 31 address *ret_path = NULL;
meillo@0 32
meillo@10 33 /* do not bounce bounces, send to postmaster instead */
meillo@15 34 if (msg->return_path->local_part[0] == '\0') {
meillo@10 35 GList *node;
meillo@0 36
meillo@10 37 ret_path = create_address_qualified("postmaster", TRUE, conf.host_name);
meillo@10 38 foreach(failed_rcpts, node) {
meillo@10 39 address *addr = (address *) (node->data);
meillo@242 40
meillo@242 41 if (addr_isequal_parent(addr, ret_path, strcasecmp)) {
meillo@10 42 logwrite(LOG_ALERT, "%s == %s: postmaster address failed\n", msg->uid, addr_string(ret_path));
meillo@10 43 return FALSE;
meillo@10 44 }
meillo@10 45 }
meillo@10 46 } else
meillo@10 47 ret_path = copy_address(msg->return_path);
meillo@0 48
meillo@10 49 DEBUG(1) debugf("sending failure notice to %s.\n", addr_string(ret_path));
meillo@0 50
meillo@10 51 if (template) {
meillo@10 52 FILE *file;
meillo@10 53 GList *var_table = var_table_conf(var_table_msg(NULL, msg));
meillo@10 54 gchar *err_msg = g_strdup_vprintf(err_fmt, args);
meillo@0 55
meillo@10 56 var_table = g_list_prepend(var_table, create_pair_string("err_msg", err_msg));
meillo@10 57 g_free(err_msg);
meillo@0 58
meillo@10 59 if ((file = fopen(template, "r"))) {
meillo@10 60 FILE *out;
meillo@10 61 gchar *cmd;
meillo@10 62 pid_t pid;
meillo@0 63
meillo@10 64 cmd = g_strdup_printf(SBINDIR "/masqmail -oi -f <> %s@%s", ret_path->local_part, ret_path->domain);
meillo@10 65 if ((out = peidopen(cmd, "w", environ, &pid, conf.mail_uid, conf.mail_gid))) {
meillo@10 66 gchar fmt[256], line[256];
meillo@10 67 int status, ret;
meillo@0 68
meillo@10 69 while ((ret = read_sockline(file, fmt, 256, 0, 0)) > 0) {
meillo@10 70 if (fmt[0] == '@') {
meillo@10 71 GList *node;
meillo@10 72 if (strncmp(fmt, "@failed_rcpts", 13) == 0) {
meillo@10 73 foreach(failed_rcpts, node) {
meillo@10 74 address *rcpt = (address *) (node->data);
meillo@10 75 fprintf(out, "\t%s\n", addr_string(rcpt));
meillo@10 76 }
meillo@10 77 } else if (strncmp(fmt, "@msg_headers", 12) == 0) {
meillo@10 78 foreach(msg->hdr_list, node) {
meillo@10 79 header *hdr = (header *) (node->data);
meillo@10 80 fputs(hdr->header, out);
meillo@10 81 }
meillo@10 82 } else if (strncmp(fmt, "@msg_body", 9) == 0) {
meillo@15 83 /* we may have to read the data at this point and remember if we did */
meillo@10 84 gboolean flag = (msg->data_list == NULL);
meillo@10 85 if (flag) {
meillo@10 86 if (!spool_read_data(msg)) {
meillo@10 87 logwrite(LOG_ALERT, "could not open data spool file %s\n", msg->uid);
meillo@10 88 }
meillo@10 89 }
meillo@10 90 foreach(msg->data_list, node) {
meillo@10 91 gchar *line = (gchar *) (node->data);
meillo@10 92 fputs(line, out);
meillo@10 93 }
meillo@10 94 if (flag)
meillo@10 95 msg_free_data(msg);
meillo@10 96 }
meillo@10 97 } else {
meillo@10 98 expand(var_table, fmt, line, 256);
meillo@10 99 fputs(line, out);
meillo@10 100 }
meillo@10 101 }
meillo@10 102
meillo@10 103 fclose(out);
meillo@10 104 waitpid(pid, &status, 0);
meillo@262 105 if ((WEXITSTATUS(status) != 0) || WIFSIGNALED(status)) {
meillo@262 106 if (WEXITSTATUS(status) != 0)
meillo@10 107 logwrite(LOG_WARNING, "child returned %d\n", WEXITSTATUS(status));
meillo@10 108 if (WIFSIGNALED(status))
meillo@10 109 logwrite(LOG_WARNING, "child got signal: %d\n", WTERMSIG(status));
meillo@10 110 } else
meillo@10 111 ok = TRUE;
meillo@10 112 } else {
meillo@10 113 logwrite(LOG_ERR, "peopen failed: %s\n", strerror(errno));
meillo@10 114 }
meillo@10 115 g_free(cmd);
meillo@10 116 fclose(file);
meillo@10 117 } else
meillo@10 118 logwrite(LOG_ALERT, "could not open failure message template %s: %s\n", conf.errmsg_file, strerror(errno));
meillo@10 119
meillo@10 120 destroy_table(var_table);
meillo@0 121 }
meillo@0 122
meillo@10 123 destroy_address(ret_path);
meillo@0 124
meillo@10 125 return ok;
meillo@0 126 }
meillo@0 127
meillo@0 128 /*
meillo@367 129 ** ival : |--|--|----|--------|--------|
meillo@367 130 ** warned: |-------W-------------W------
meillo@367 131 ** result: |nnnyyyynnnnyyyyyyyyyynnnnnnn
meillo@0 132 */
meillo@10 133 static gboolean
meillo@366 134 warn_msg_is_due(message *msg)
meillo@0 135 {
meillo@10 136 time_t now = time(NULL);
meillo@10 137
meillo@10 138 GList *node;
meillo@10 139 for (node = g_list_last(conf.warn_intervals); node; node = g_list_previous(node)) {
meillo@10 140 gchar *str_ival = (gchar *) (node->data);
meillo@254 141 gint ival = time_interval(str_ival);
meillo@10 142 if (ival >= 0) {
meillo@10 143 DEBUG(5) debugf("ival = %d\n", ival);
meillo@10 144 DEBUG(5) debugf("now - msg->received_time = %d\n", now - msg->received_time);
meillo@10 145 if ((now - msg->received_time) > ival) {
meillo@10 146 if (msg->warned_time != 0) {
meillo@10 147 if ((msg->warned_time - msg->received_time) < ival)
meillo@10 148 return TRUE;
meillo@10 149 } else
meillo@10 150 return TRUE;
meillo@10 151 }
meillo@10 152 } else
meillo@10 153 logwrite(LOG_WARNING, "invalid time interval: %s\n", str_ival);
meillo@10 154 }
meillo@10 155 return FALSE;
meillo@0 156 }
meillo@0 157
meillo@10 158 gboolean
meillo@367 159 warn_msg(message *msg, gchar *template, GList *defered_rcpts, gchar *err_fmt,
meillo@367 160 va_list args)
meillo@0 161 {
meillo@10 162 time_t now = time(NULL);
meillo@0 163
meillo@10 164 if (warn_msg_is_due(msg)) {
meillo@10 165 if (fail_msg(msg, template, defered_rcpts, err_fmt, args)) {
meillo@10 166 msg->warned_time = now;
meillo@10 167 return TRUE;
meillo@10 168 } else
meillo@10 169 return FALSE;
meillo@10 170 }
meillo@10 171 return TRUE;
meillo@0 172 }