No empty .Rs/.Re
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / global / deliver_pass.c
blob2c6f7d6f1415b177e7b745051c2c8db20978fdd9
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* deliver_pass 3
6 /* SUMMARY
7 /* deliver request pass_through
8 /* SYNOPSIS
9 /* #include <deliver_request.h>
11 /* int deliver_pass(class, service, request, recipient)
12 /* const char *class;
13 /* const char *service;
14 /* DELIVER_REQUEST *request;
15 /* RECIPIENT *recipient;
17 /* int deliver_pass_all(class, service, request)
18 /* const char *class;
19 /* const char *service;
20 /* DELIVER_REQUEST *request;
21 /* DESCRIPTION
22 /* This module implements the client side of the `queue manager
23 /* to delivery agent' protocol, passing one recipient on from
24 /* one delivery agent to another.
26 /* deliver_pass() delegates delivery of the named recipient.
28 /* deliver_pass_all() delegates an entire delivery request.
30 /* Arguments:
31 /* .IP class
32 /* Destination delivery agent service class
33 /* .IP service
34 /* String of the form \fItransport\fR:\fInexthop\fR. Either transport
35 /* or nexthop are optional. For details see the transport map manual page.
36 /* .IP request
37 /* Delivery request with queue file information.
38 /* .IP recipient
39 /* Recipient information. See recipient_list(3).
40 /* DIAGNOSTICS
41 /* LICENSE
42 /* .ad
43 /* .fi
44 /* The Secure Mailer license must be distributed with this software.
45 /* BUGS
46 /* One recipient at a time; this is OK for mailbox deliveries.
48 /* Hop status information cannot be passed back.
49 /* AUTHOR(S)
50 /* Wietse Venema
51 /* IBM T.J. Watson Research
52 /* P.O. Box 704
53 /* Yorktown Heights, NY 10598, USA
54 /*--*/
56 /* System library. */
58 #include <sys_defs.h>
60 /* Utility library. */
62 #include <msg.h>
63 #include <vstring.h>
64 #include <vstream.h>
65 #include <split_at.h>
66 #include <mymalloc.h>
68 /* Global library. */
70 #include <mail_params.h>
71 #include <deliver_pass.h>
72 #include <dsb_scan.h>
73 #include <defer.h>
74 #include <rcpt_print.h>
76 #define DELIVER_PASS_DEFER 1
77 #define DELIVER_PASS_UNKNOWN 2
79 /* deliver_pass_initial_reply - retrieve initial delivery process response */
81 static int deliver_pass_initial_reply(VSTREAM *stream)
83 int stat;
85 if (attr_scan(stream, ATTR_FLAG_STRICT,
86 ATTR_TYPE_INT, MAIL_ATTR_STATUS, &stat,
87 ATTR_TYPE_END) != 1) {
88 msg_warn("%s: malformed response", VSTREAM_PATH(stream));
89 stat = -1;
91 return (stat);
94 /* deliver_pass_send_request - send delivery request to delivery process */
96 static int deliver_pass_send_request(VSTREAM *stream, DELIVER_REQUEST *request,
97 const char *nexthop,
98 RECIPIENT *rcpt)
100 int stat;
102 attr_print(stream, ATTR_FLAG_NONE,
103 ATTR_TYPE_INT, MAIL_ATTR_FLAGS, request->flags,
104 ATTR_TYPE_STR, MAIL_ATTR_QUEUE, request->queue_name,
105 ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, request->queue_id,
106 ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, request->data_offset,
107 ATTR_TYPE_LONG, MAIL_ATTR_SIZE, request->data_size,
108 ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, nexthop,
109 ATTR_TYPE_STR, MAIL_ATTR_ENCODING, request->encoding,
110 ATTR_TYPE_STR, MAIL_ATTR_SENDER, request->sender,
111 ATTR_TYPE_STR, MAIL_ATTR_DSN_ENVID, request->dsn_envid,
112 ATTR_TYPE_INT, MAIL_ATTR_DSN_RET, request->dsn_ret,
113 ATTR_TYPE_FUNC, msg_stats_print, (void *) &request->msg_stats,
114 /* XXX Should be encapsulated with ATTR_TYPE_FUNC. */
115 ATTR_TYPE_STR, MAIL_ATTR_LOG_CLIENT_NAME, request->client_name,
116 ATTR_TYPE_STR, MAIL_ATTR_LOG_CLIENT_ADDR, request->client_addr,
117 ATTR_TYPE_STR, MAIL_ATTR_LOG_CLIENT_PORT, request->client_port,
118 ATTR_TYPE_STR, MAIL_ATTR_LOG_PROTO_NAME, request->client_proto,
119 ATTR_TYPE_STR, MAIL_ATTR_LOG_HELO_NAME, request->client_helo,
120 /* XXX Should be encapsulated with ATTR_TYPE_FUNC. */
121 ATTR_TYPE_STR, MAIL_ATTR_SASL_METHOD, request->sasl_method,
122 ATTR_TYPE_STR, MAIL_ATTR_SASL_USERNAME, request->sasl_username,
123 ATTR_TYPE_STR, MAIL_ATTR_SASL_SENDER, request->sasl_sender,
124 /* XXX Ditto if we want to pass TLS certificate info. */
125 ATTR_TYPE_STR, MAIL_ATTR_RWR_CONTEXT, request->rewrite_context,
126 ATTR_TYPE_INT, MAIL_ATTR_RCPT_COUNT, 1,
127 ATTR_TYPE_END);
128 attr_print(stream, ATTR_FLAG_NONE,
129 ATTR_TYPE_FUNC, rcpt_print, (void *) rcpt,
130 ATTR_TYPE_END);
132 if (vstream_fflush(stream)) {
133 msg_warn("%s: bad write: %m", VSTREAM_PATH(stream));
134 stat = -1;
135 } else {
136 stat = 0;
138 return (stat);
141 /* deliver_pass_final_reply - retrieve final delivery status response */
143 static int deliver_pass_final_reply(VSTREAM *stream, DSN_BUF *dsb)
145 int stat;
147 if (attr_scan(stream, ATTR_FLAG_STRICT,
148 ATTR_TYPE_FUNC, dsb_scan, (void *) dsb,
149 ATTR_TYPE_INT, MAIL_ATTR_STATUS, &stat,
150 ATTR_TYPE_END) != 2) {
151 msg_warn("%s: malformed response", VSTREAM_PATH(stream));
152 return (DELIVER_PASS_UNKNOWN);
153 } else {
154 return (stat ? DELIVER_PASS_DEFER : 0);
158 /* deliver_pass - deliver one per-site queue entry */
160 int deliver_pass(const char *class, const char *service,
161 DELIVER_REQUEST *request,
162 RECIPIENT *rcpt)
164 VSTREAM *stream;
165 DSN_BUF *dsb;
166 DSN dsn;
167 int status;
168 char *saved_service;
169 char *transport;
170 char *nexthop;
173 * Parse service into transport:nexthop form, and allow for omission of
174 * optional fields
176 transport = saved_service = mystrdup(service);
177 if ((nexthop = split_at(saved_service, ':')) == 0 || *nexthop == 0)
178 nexthop = request->nexthop;
179 if (*transport == 0)
180 msg_fatal("missing transport name in \"%s\"", service);
183 * Initialize.
185 stream = mail_connect_wait(class, transport);
186 dsb = dsb_create();
189 * Get the delivery process initial response. Send the queue file info
190 * and recipient info to the delivery process. Retrieve the delivery
191 * agent status report. The numerical status code indicates if delivery
192 * should be tried again. The reason text is sent only when a destination
193 * should be avoided for a while, so that the queue manager can log why
194 * it does not even try to schedule delivery to the affected recipients.
195 * XXX Can't pass back hop status info because the problem is with a
196 * different transport.
198 if (deliver_pass_initial_reply(stream) != 0
199 || deliver_pass_send_request(stream, request, nexthop, rcpt) != 0) {
200 (void) DSN_SIMPLE(&dsn, "4.3.0", "mail transport unavailable");
201 status = defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
202 request->queue_id, &request->msg_stats,
203 rcpt, "none", &dsn);
204 } else if ((status = deliver_pass_final_reply(stream, dsb))
205 == DELIVER_PASS_UNKNOWN) {
206 (void) DSN_SIMPLE(&dsn, "4.3.0", "unknown mail transport error");
207 status = defer_append(DEL_REQ_TRACE_FLAGS(request->flags),
208 request->queue_id, &request->msg_stats,
209 rcpt, "none", &dsn);
213 * Clean up.
215 vstream_fclose(stream);
216 dsb_free(dsb);
217 myfree(saved_service);
219 return (status);
222 /* deliver_pass_all - pass entire delivery request */
224 int deliver_pass_all(const char *class, const char *service,
225 DELIVER_REQUEST *request)
227 RECIPIENT_LIST *list;
228 RECIPIENT *rcpt;
229 int status = 0;
232 * XXX We should find out if the target transport can handle
233 * multi-recipient requests. Unfortunately such code is hard to test,
234 * rarely used, and therefore will be buggy.
236 list = &request->rcpt_list;
237 for (rcpt = list->info; rcpt < list->info + list->len; rcpt++)
238 status |= deliver_pass(class, service, request, rcpt);
239 return (status);