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