1/*++ 2/* NAME 3/* bounce_trace_service 3 4/* SUMMARY 5/* send status report to sender, server side 6/* SYNOPSIS 7/* #include "bounce_service.h" 8/* 9/* int bounce_trace_service(flags, queue_name, queue_id, encoding, 10/* sender, char *envid, int ret, templates) 11/* int flags; 12/* char *queue_name; 13/* char *queue_id; 14/* char *encoding; 15/* char *sender; 16/* char *envid; 17/* int ret; 18/* BOUNCE_TEMPLATES *templates; 19/* DESCRIPTION 20/* This module implements the server side of the trace_flush() 21/* (send delivery notice) request. The logfile 22/* is removed after the notice is posted. 23/* 24/* A status report includes a prelude with human-readable text, 25/* a DSN-style report, and the email message that was subject of 26/* the status report. 27/* 28/* When a status report is sent, the sender address is the empty 29/* address. 30/* DIAGNOSTICS 31/* Fatal error: error opening existing file. 32/* BUGS 33/* SEE ALSO 34/* bounce(3) basic bounce service client interface 35/* LICENSE 36/* .ad 37/* .fi 38/* The Secure Mailer license must be distributed with this software. 39/* AUTHOR(S) 40/* Wietse Venema 41/* IBM T.J. Watson Research 42/* P.O. Box 704 43/* Yorktown Heights, NY 10598, USA 44/*--*/ 45 46/* System library. */ 47 48#include <sys_defs.h> 49#include <fcntl.h> 50#include <errno.h> 51#include <string.h> 52#include <ctype.h> 53 54/* Utility library. */ 55 56#include <msg.h> 57#include <vstream.h> 58 59/* Global library. */ 60 61#include <mail_params.h> 62#include <mail_queue.h> 63#include <post_mail.h> 64#include <mail_addr.h> 65#include <mail_error.h> 66#include <dsn_mask.h> 67#include <deliver_request.h> /* USR_VRFY and RECORD flags */ 68 69/* Application-specific. */ 70 71#include "bounce_service.h" 72 73#define STR vstring_str 74 75/* bounce_trace_service - send a delivery status notice */ 76 77int bounce_trace_service(int flags, char *service, char *queue_name, 78 char *queue_id, char *encoding, 79 char *recipient, char *dsn_envid, 80 int unused_dsn_ret, 81 BOUNCE_TEMPLATES *ts) 82{ 83 BOUNCE_INFO *bounce_info; 84 int bounce_status = 1; 85 VSTREAM *bounce; 86 int notify_mask = name_mask(VAR_NOTIFY_CLASSES, mail_error_masks, 87 var_notify_classes); 88 VSTRING *new_id; 89 int count; 90 const char *sender; 91 92 /* 93 * For consistency with fail/delay notifications, send notification for a 94 * non-bounce message as a single-bounce message, send notification for a 95 * single-bounce message as a double-bounce message, and drop requests to 96 * send notification for a double-bounce message. 97 */ 98#define NULL_SENDER MAIL_ADDR_EMPTY /* special address */ 99 100 if (strcasecmp(recipient, mail_addr_double_bounce()) == 0) { 101 msg_info("%s: not sending trace/success notification for " 102 "double-bounce message", queue_id); 103 return (0); 104 } else if (*recipient == 0) { 105 if ((notify_mask & MAIL_ERROR_2BOUNCE) != 0) { 106 recipient = var_2bounce_rcpt; 107 sender = mail_addr_double_bounce(); 108 } else { 109 msg_info("%s: not sending trace/success notification " 110 "for single-bounce message", queue_id); 111 if (mail_queue_remove(service, queue_id) && errno != ENOENT) 112 msg_fatal("remove %s %s: %m", service, queue_id); 113 return (0); 114 } 115 } else { 116 /* Always send notification for non-bounce message. */ 117 sender = NULL_SENDER; 118 } 119 120 /* 121 * Initialize. Open queue file, bounce log, etc. 122 * 123 * XXX DSN The trace service produces information from the trace logfile 124 * which is used for three types of reports: 125 * 126 * a) "what-if" reports that show what would happen without actually 127 * delivering mail (sendmail -bv). 128 * 129 * b) A report of actual deliveries (sendmail -v). 130 * 131 * c) DSN NOTIFY=SUCCESS reports of successful delivery ("delivered", 132 * "expanded" or "relayed"). 133 */ 134#define NON_DSN_FLAGS (DEL_REQ_FLAG_USR_VRFY | DEL_REQ_FLAG_RECORD) 135 136 bounce_info = bounce_mail_init(service, queue_name, queue_id, 137 encoding, dsn_envid, 138 flags & NON_DSN_FLAGS ? 139 ts->verify : ts->success); 140 141 /* 142 * XXX With multi-recipient mail some queue file recipients may have 143 * NOTIFY=SUCCESS and others not. Depending on what subset of recipients 144 * are delivered, a trace file may or may not be created. Even when the 145 * last partial delivery attempt had no NOTIFY=SUCCESS recipients, a 146 * trace file may still exist from a previous partial delivery attempt. 147 * So as long as any recipient in the original queue file had 148 * NOTIFY=SUCCESS we have to always look for the trace file and be 149 * prepared for the file not to exist. 150 * 151 * See also comments in qmgr/qmgr_active.c. 152 */ 153 if (bounce_info->log_handle == 0) { 154 if (msg_verbose) 155 msg_info("%s: no trace file -- not sending a notification", 156 queue_id); 157 bounce_mail_free(bounce_info); 158 return (0); 159 } 160#define NULL_TRACE_FLAGS 0 161 162 /* 163 * Send a single bounce with a template message header, some boilerplate 164 * text that pretends that we are a polite mail system, the text with 165 * per-recipient status, and a copy of the original message. 166 * 167 * XXX DSN We use the same trace file for "what-if", "verbose delivery" and 168 * "success" delivery reports. This saves file system overhead because 169 * there are fewer potential left-over files to remove up when we create 170 * a new queue file. 171 */ 172 new_id = vstring_alloc(10); 173 if ((bounce = post_mail_fopen_nowait(sender, recipient, 174 INT_FILT_MASK_BOUNCE, 175 NULL_TRACE_FLAGS, 176 new_id)) != 0) { 177 count = -1; 178 if (bounce_header(bounce, bounce_info, recipient, 179 NO_POSTMASTER_COPY) == 0 180 && bounce_boilerplate(bounce, bounce_info) == 0 181 && (count = bounce_diagnostic_log(bounce, bounce_info, 182 DSN_NOTIFY_OVERRIDE)) > 0 183 && bounce_header_dsn(bounce, bounce_info) == 0 184 && bounce_diagnostic_dsn(bounce, bounce_info, 185 DSN_NOTIFY_OVERRIDE) > 0) { 186 bounce_original(bounce, bounce_info, DSN_RET_HDRS); 187 bounce_status = post_mail_fclose(bounce); 188 if (bounce_status == 0) 189 msg_info("%s: sender delivery status notification: %s", 190 queue_id, STR(new_id)); 191 } else { 192 (void) vstream_fclose(bounce); 193 if (count == 0) 194 bounce_status = 0; 195 } 196 } 197 198 /* 199 * Examine the completion status. Delete the trace log file only when the 200 * status notice was posted successfully. 201 */ 202 if (bounce_status == 0 && mail_queue_remove(service, queue_id) 203 && errno != ENOENT) 204 msg_fatal("remove %s %s: %m", service, queue_id); 205 206 /* 207 * Cleanup. 208 */ 209 bounce_mail_free(bounce_info); 210 vstring_free(new_id); 211 212 return (bounce_status); 213} 214