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