masqmail

diff src/fail_msg.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/fail_msg.c	Fri Sep 26 17:05:23 2008 +0200
     1.3 @@ -0,0 +1,177 @@
     1.4 +/*  MasqMail
     1.5 +    Copyright (C) 2000-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., 675 Mass Ave, Cambridge, MA 02139, USA.
    1.20 + */
    1.21 +
    1.22 +#include <sys/wait.h>
    1.23 +
    1.24 +#include "masqmail.h"
    1.25 +#include "peopen.h"
    1.26 +#include "readsock.h"
    1.27 +
    1.28 +gboolean fail_msg(message *msg, gchar *template,
    1.29 +		  GList *failed_rcpts, gchar *err_fmt, va_list args)
    1.30 +{
    1.31 +  gboolean ok = FALSE;
    1.32 +  address *ret_path = NULL;
    1.33 +
    1.34 +  /* do not bounce bounces, send to postmaster instead */
    1.35 +  if(msg->return_path->local_part[0] == 0){
    1.36 +    GList *node;
    1.37 +
    1.38 +    ret_path = create_address_qualified("postmaster", TRUE, conf.host_name);
    1.39 +    foreach(failed_rcpts, node){
    1.40 +      address *addr = (address *)(node->data);
    1.41 +      if(addr_isequal_parent(addr, ret_path)){
    1.42 +	logwrite(LOG_ALERT, "%s == %s: postmaster address failed\n",
    1.43 +		 msg->uid, addr_string(ret_path));
    1.44 +	return FALSE;
    1.45 +      }
    1.46 +    }
    1.47 +  }else
    1.48 +    ret_path = copy_address(msg->return_path);
    1.49 +
    1.50 +  DEBUG(1) debugf("sending failure notice to %s.\n", addr_string(ret_path));
    1.51 +
    1.52 +  if(template){
    1.53 +    FILE *file;
    1.54 +    GList *var_table = var_table_conf(var_table_msg(NULL, msg));
    1.55 +    gchar *err_msg = g_strdup_vprintf(err_fmt, args);
    1.56 +
    1.57 +    var_table = g_list_prepend(var_table, create_pair_string("err_msg", err_msg));
    1.58 +    g_free(err_msg);
    1.59 +
    1.60 +    if((file = fopen(template, "r"))){
    1.61 +      FILE *out;
    1.62 +      gchar *cmd;
    1.63 +      pid_t pid;
    1.64 +
    1.65 +      //      cmd = g_strdup_printf(SBINDIR"/masqmail -oi -f \"<>\" %s@%s",
    1.66 +      //			    ret_path->local_part, ret_path->domain);
    1.67 +      cmd = g_strdup_printf(SBINDIR"/masqmail -oi -f <> %s@%s",
    1.68 +			    ret_path->local_part, ret_path->domain);
    1.69 +      if((out = peidopen(cmd, "w", environ, &pid, conf.mail_uid, conf.mail_gid))){
    1.70 +	gchar fmt[256], line[256];
    1.71 +	int status, ret;
    1.72 +
    1.73 +	while((ret = read_sockline(file, fmt, 256, 0, 0)) > 0){
    1.74 +	  if(fmt[0] == '@'){
    1.75 +	    GList *node;
    1.76 +	    if(strncmp(fmt, "@failed_rcpts", 13) == 0){
    1.77 +	      foreach(failed_rcpts, node){
    1.78 +		address *rcpt = (address *)(node->data);
    1.79 +		fprintf(out, "\t%s\n", addr_string(rcpt));
    1.80 +	      }
    1.81 +	    }else if(strncmp(fmt, "@msg_headers", 12) == 0){
    1.82 +	      foreach(msg->hdr_list, node){
    1.83 +		header *hdr = (header *)(node->data);
    1.84 +		fputs(hdr->header, out);
    1.85 +	      }
    1.86 +	    }else if(strncmp(fmt, "@msg_body", 9) == 0){
    1.87 +	      /* we may have to read the data at this point
    1.88 +		 and remember if we did */
    1.89 +	      gboolean flag = (msg->data_list == NULL);
    1.90 +	      if(flag){
    1.91 +		if(!spool_read_data(msg)){
    1.92 +		  logwrite(LOG_ALERT, "could not open data spool file %s\n",
    1.93 +			   msg->uid);
    1.94 +		}
    1.95 +	      }
    1.96 +	      foreach(msg->data_list, node){
    1.97 +		gchar *line = (gchar *)(node->data);
    1.98 +		fputs(line, out);
    1.99 +	      }
   1.100 +	      if(flag) msg_free_data(msg);
   1.101 +	    }
   1.102 +	  }else{
   1.103 +	    expand(var_table, fmt, line, 256);
   1.104 +	    fputs(line, out);
   1.105 +	  }
   1.106 +	}
   1.107 +
   1.108 +	fclose(out);
   1.109 +	waitpid(pid, &status, 0);
   1.110 +	if((WEXITSTATUS(status) != EXIT_SUCCESS) || WIFSIGNALED(status)){
   1.111 +	  if(WEXITSTATUS(status) != EXIT_SUCCESS)
   1.112 +	    logwrite(LOG_WARNING, "child returned %d\n", WEXITSTATUS(status));
   1.113 +	  if(WIFSIGNALED(status))
   1.114 +	    logwrite(LOG_WARNING, "child got signal: %d\n", WTERMSIG(status));
   1.115 +	}else ok = TRUE;
   1.116 +      }else{
   1.117 +	logwrite(LOG_ERR, "peopen failed: %s\n", strerror(errno));
   1.118 +      }
   1.119 +      g_free(cmd);
   1.120 +      fclose(file);
   1.121 +    }else
   1.122 +      logwrite(LOG_ALERT, "could not open failure message template %s: %s\n",
   1.123 +	       conf.errmsg_file, strerror(errno));
   1.124 +
   1.125 +    destroy_table(var_table);
   1.126 +  }
   1.127 +    
   1.128 +  destroy_address(ret_path);
   1.129 +
   1.130 +  return ok;
   1.131 +}
   1.132 +
   1.133 +/*
   1.134 +ival  : |--|--|----|--------|--------|
   1.135 +warned: |-------W-------------W------
   1.136 +result: |nnnyyyynnnnyyyyyyyyyynnnnnnn
   1.137 +*/
   1.138 +
   1.139 +static
   1.140 +gboolean warn_msg_is_due(message *msg)
   1.141 +{
   1.142 +  time_t now = time(NULL);
   1.143 +  gint dummy;
   1.144 +  
   1.145 +  GList *node;
   1.146 +  for(node = g_list_last(conf.warn_intervals); node; node = g_list_previous(node)){
   1.147 +    gchar *str_ival = (gchar *)(node->data);
   1.148 +    gint ival = time_interval(str_ival, &dummy);
   1.149 +    if(ival >= 0){
   1.150 +      DEBUG(5) debugf("ival = %d\n", ival);
   1.151 +      DEBUG(5) debugf("now - msg->received_time = %d\n", now - msg->received_time);
   1.152 +      if((now - msg->received_time) > ival){
   1.153 +	if(msg->warned_time != 0){
   1.154 +	  if((msg->warned_time - msg->received_time) < ival)
   1.155 +	    return TRUE;
   1.156 +	}else
   1.157 +	  return TRUE;
   1.158 +      }
   1.159 +    }else
   1.160 +      logwrite(LOG_WARNING, "invalid time interval: %s\n", str_ival);
   1.161 +  }
   1.162 +  return FALSE;
   1.163 +}
   1.164 +
   1.165 +gboolean warn_msg(message *msg, gchar *template,
   1.166 +		  GList *defered_rcpts, gchar *err_fmt, va_list args)
   1.167 +{
   1.168 +  time_t now = time(NULL);
   1.169 +
   1.170 +  if(warn_msg_is_due(msg)){
   1.171 +    if(fail_msg(msg, template, defered_rcpts, err_fmt, args)){
   1.172 +      msg->warned_time = now;
   1.173 +      return TRUE;
   1.174 +    }else
   1.175 +      return FALSE;
   1.176 +  }
   1.177 +  return TRUE;
   1.178 +}
   1.179 +
   1.180 +