7 /* deliver request pass_through
9 /* #include <deliver_request.h>
11 /* int deliver_pass(class, service, request, recipient)
13 /* const char *service;
14 /* DELIVER_REQUEST *request;
15 /* RECIPIENT *recipient;
17 /* int deliver_pass_all(class, service, request)
19 /* const char *service;
20 /* DELIVER_REQUEST *request;
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.
32 /* Destination delivery agent service class
34 /* String of the form \fItransport\fR:\fInexthop\fR. Either transport
35 /* or nexthop are optional. For details see the transport map manual page.
37 /* Delivery request with queue file information.
39 /* Recipient information. See recipient_list(3).
44 /* The Secure Mailer license must be distributed with this software.
46 /* One recipient at a time; this is OK for mailbox deliveries.
48 /* Hop status information cannot be passed back.
51 /* IBM T.J. Watson Research
53 /* Yorktown Heights, NY 10598, USA
60 /* Utility library. */
70 #include <mail_params.h>
71 #include <deliver_pass.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
)
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
));
94 /* deliver_pass_send_request - send delivery request to delivery process */
96 static int deliver_pass_send_request(VSTREAM
*stream
, DELIVER_REQUEST
*request
,
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,
128 attr_print(stream
, ATTR_FLAG_NONE
,
129 ATTR_TYPE_FUNC
, rcpt_print
, (void *) rcpt
,
132 if (vstream_fflush(stream
)) {
133 msg_warn("%s: bad write: %m", VSTREAM_PATH(stream
));
141 /* deliver_pass_final_reply - retrieve final delivery status response */
143 static int deliver_pass_final_reply(VSTREAM
*stream
, DSN_BUF
*dsb
)
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
);
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
,
173 * Parse service into transport:nexthop form, and allow for omission of
176 transport
= saved_service
= mystrdup(service
);
177 if ((nexthop
= split_at(saved_service
, ':')) == 0 || *nexthop
== 0)
178 nexthop
= request
->nexthop
;
180 msg_fatal("missing transport name in \"%s\"", service
);
185 stream
= mail_connect_wait(class, transport
);
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
,
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
,
215 vstream_fclose(stream
);
217 myfree(saved_service
);
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
;
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
);