5
/* asynchronous bounce/defer service client
7
/* #include <abounce.h>
9
/* void abounce_flush(flags, queue, id, encoding, sender,
14
/* const char *encoding;
15
/* const char *sender;
16
/* void (*callback)(int status, char *context);
19
/* void abounce_flush_verp(flags, queue, id, encoding,
20
/* sender, verp, callback, context)
24
/* const char *encoding;
25
/* const char *sender;
27
/* void (*callback)(int status, char *context);
30
/* void adefer_flush(flags, queue, id, encoding, sender,
35
/* const char *encoding;
36
/* const char *sender;
37
/* void (*callback)(int status, char *context);
40
/* void adefer_flush_verp(flags, queue, id, encoding,
41
/* sender, verp, callback, context)
45
/* const char *encoding;
46
/* const char *sender;
48
/* void (*callback)(int status, char *context);
51
/* void adefer_warn(flags, queue, id, encoding, sender,
56
/* const char *encoding;
57
/* const char *sender;
58
/* void (*callback)(int status, char *context);
61
/* This module implements an asynchronous interface to the
62
/* bounce/defer service for submitting sender notifications
63
/* without waiting for completion of the request.
65
/* abounce_flush() bounces the specified message to
66
/* the specified sender, including the bounce log that was
67
/* built with bounce_append().
69
/* abounce_flush_verp() is like abounce_flush() but sends
70
/* one VERP style notification per undeliverable recipient.
72
/* adefer_flush() bounces the specified message to
73
/* the specified sender, including the defer log that was
74
/* built with defer_append().
75
/* adefer_flush() requests that the deferred recipients are deleted
76
/* from the original queue file.
78
/* adefer_flush_verp() is like adefer_flush() but sends
79
/* one VERP style notification per undeliverable recipient.
81
/* adefer_warn() sends a "mail is delayed" notification to
82
/* the specified sender, including the defer log that was
83
/* built with defer_append().
87
/* The bitwise OR of zero or more of the following (specify
88
/* BOUNCE_FLAG_NONE to request no special processing):
90
/* .IP BOUNCE_FLAG_CLEAN
91
/* Delete the bounce log in case of an error (as in: pretend
92
/* that we never even tried to bounce this message).
93
/* .IP BOUNCE_FLAG_COPY
94
/* Request that a postmaster copy is sent.
97
/* The message queue name of the original message file.
99
/* The message queue id if the original message file. The bounce log
100
/* file has the same name as the original message file.
102
/* The body content encoding: MAIL_ATTR_ENC_{7BIT,8BIT,NONE}.
104
/* The sender envelope address.
106
/* VERP delimiter characters.
108
/* Name of a routine that receives the notification status as
109
/* documented for bounce_flush() or defer_flush().
111
/* Application-specific context that is passed through to the
112
/* callback routine. Use proper casts or the world will come
115
/* In case of success, these functions log the action, and return a
116
/* zero result via the callback routine. Otherwise, the functions
117
/* return a non-zero result via the callback routine, and when
118
/* BOUNCE_FLAG_CLEAN is disabled, log that message delivery is deferred.
122
/* The Secure Mailer license must be distributed with this software.
125
/* IBM T.J. Watson Research
127
/* Yorktown Heights, NY 10598, USA
130
/* System library. */
132
#include <sys_defs.h>
134
/* Utility library. */
137
#include <mymalloc.h>
141
/* Global library. */
143
#include <mail_params.h>
144
#include <mail_proto.h>
147
/* Application-specific. */
150
* Each bounce/defer flush/warn request is implemented by sending the
151
* request to the bounce/defer server, and by creating a pseudo thread that
152
* suspends itself until the server replies (or dies). Upon wakeup, the
153
* pseudo thread delivers the request completion status to the application
154
* and destroys itself. The structure below maintains all the necessary
155
* request state while the pseudo thread is suspended.
158
int command; /* bounce request type */
159
int flags; /* bounce options */
160
char *id; /* queue ID for logging */
161
ABOUNCE_FN callback; /* application callback */
162
char *context; /* application context */
163
VSTREAM *fp; /* server I/O handle */
166
/* abounce_done - deliver status to application and clean up pseudo thread */
168
static void abounce_done(ABOUNCE *ap, int status)
170
(void) vstream_fclose(ap->fp);
171
if (status != 0 && (ap->flags & BOUNCE_FLAG_CLEAN) == 0)
172
msg_info("%s: status=deferred (%s failed)", ap->id,
173
ap->command == BOUNCE_CMD_FLUSH ? "bounce" :
174
ap->command == BOUNCE_CMD_WARN ? "delay warning" :
176
ap->callback(status, ap->context);
181
/* abounce_event - resume pseudo thread after server reply event */
183
static void abounce_event(int unused_event, char *context)
185
ABOUNCE *ap = (ABOUNCE *) context;
188
event_disable_readwrite(vstream_fileno(ap->fp));
189
abounce_done(ap, attr_scan(ap->fp, ATTR_FLAG_STRICT,
190
ATTR_TYPE_NUM, MAIL_ATTR_STATUS, &status,
191
ATTR_TYPE_END) == 1 ? status : -1);
194
/* abounce_request_verp - suspend pseudo thread until server reply event */
196
static void abounce_request_verp(const char *class, const char *service,
197
int command, int flags,
198
const char *queue, const char *id,
199
const char *encoding,
208
* Save pseudo thread state. Connect to the server. Send the request and
209
* suspend the pseudo thread until the server replies (or dies).
211
ap = (ABOUNCE *) mymalloc(sizeof(*ap));
212
ap->command = command;
214
ap->id = mystrdup(id);
215
ap->callback = callback;
216
ap->context = context;
217
ap->fp = mail_connect_wait(class, service);
219
if (attr_print(ap->fp, ATTR_FLAG_NONE,
220
ATTR_TYPE_NUM, MAIL_ATTR_NREQ, command,
221
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
222
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
223
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
224
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
225
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
226
ATTR_TYPE_STR, MAIL_ATTR_VERPDL, verp,
228
&& vstream_fflush(ap->fp) == 0) {
229
event_enable_read(vstream_fileno(ap->fp), abounce_event, (char *) ap);
231
abounce_done(ap, -1);
235
/* abounce_flush_verp - asynchronous bounce flush */
237
void abounce_flush_verp(int flags, const char *queue, const char *id,
238
const char *encoding, const char *sender,
239
const char *verp, ABOUNCE_FN callback,
242
abounce_request_verp(MAIL_CLASS_PRIVATE, var_bounce_service,
243
BOUNCE_CMD_VERP, flags, queue, id, encoding,
244
sender, verp, callback, context);
247
/* adefer_flush_verp - asynchronous defer flush */
249
void adefer_flush_verp(int flags, const char *queue, const char *id,
250
const char *encoding, const char *sender,
251
const char *verp, ABOUNCE_FN callback,
254
flags |= BOUNCE_FLAG_DELRCPT;
255
abounce_request_verp(MAIL_CLASS_PRIVATE, var_defer_service,
256
BOUNCE_CMD_VERP, flags, queue, id, encoding,
257
sender, verp, callback, context);
260
/* abounce_request - suspend pseudo thread until server reply event */
262
static void abounce_request(const char *class, const char *service,
263
int command, int flags,
264
const char *queue, const char *id,
265
const char *encoding, const char *sender,
266
ABOUNCE_FN callback, char *context)
271
* Save pseudo thread state. Connect to the server. Send the request and
272
* suspend the pseudo thread until the server replies (or dies).
274
ap = (ABOUNCE *) mymalloc(sizeof(*ap));
275
ap->command = command;
277
ap->id = mystrdup(id);
278
ap->callback = callback;
279
ap->context = context;
280
ap->fp = mail_connect_wait(class, service);
282
if (attr_print(ap->fp, ATTR_FLAG_NONE,
283
ATTR_TYPE_NUM, MAIL_ATTR_NREQ, command,
284
ATTR_TYPE_NUM, MAIL_ATTR_FLAGS, flags,
285
ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue,
286
ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, id,
287
ATTR_TYPE_STR, MAIL_ATTR_ENCODING, encoding,
288
ATTR_TYPE_STR, MAIL_ATTR_SENDER, sender,
290
&& vstream_fflush(ap->fp) == 0) {
291
event_enable_read(vstream_fileno(ap->fp), abounce_event, (char *) ap);
293
abounce_done(ap, -1);
297
/* abounce_flush - asynchronous bounce flush */
299
void abounce_flush(int flags, const char *queue, const char *id,
300
const char *encoding, const char *sender,
301
ABOUNCE_FN callback, char *context)
303
abounce_request(MAIL_CLASS_PRIVATE, var_bounce_service, BOUNCE_CMD_FLUSH,
304
flags, queue, id, encoding, sender, callback, context);
307
/* adefer_flush - asynchronous defer flush */
309
void adefer_flush(int flags, const char *queue, const char *id,
310
const char *encoding, const char *sender,
311
ABOUNCE_FN callback, char *context)
313
flags |= BOUNCE_FLAG_DELRCPT;
314
abounce_request(MAIL_CLASS_PRIVATE, var_defer_service, BOUNCE_CMD_FLUSH,
315
flags, queue, id, encoding, sender, callback, context);
318
/* adefer_warn - send copy of defer log to sender as warning bounce */
320
void adefer_warn(int flags, const char *queue, const char *id,
321
const char *encoding, const char *sender,
322
ABOUNCE_FN callback, char *context)
324
abounce_request(MAIL_CLASS_PRIVATE, var_defer_service, BOUNCE_CMD_WARN,
325
flags, queue, id, encoding, sender, callback, context);