7 /* asynchronous bounce/defer service client
9 /* #include <abounce.h>
11 /* void abounce_flush(flags, queue, id, encoding, sender,
12 /* dsn_envid, dsn_ret, callback, context)
16 /* const char *encoding;
17 /* const char *sender;
18 /* const char *dsn_envid;
20 /* void (*callback)(int status, char *context);
23 /* void abounce_flush_verp(flags, queue, id, encoding, sender,
24 /* dsn_envid, dsn_ret, verp, callback, context)
28 /* const char *encoding;
29 /* const char *sender;
30 /* const char *dsn_envid;
33 /* void (*callback)(int status, char *context);
36 /* void adefer_flush(flags, queue, id, encoding, sender,
37 /* dsn_envid, dsn_ret, callback, context)
41 /* const char *encoding;
42 /* const char *sender;
43 /* const char *dsn_envid;
45 /* void (*callback)(int status, char *context);
48 /* void adefer_flush_verp(flags, queue, id, encoding, sender,
49 /* dsn_envid, dsn_ret, verp, callback, context)
53 /* const char *encoding;
54 /* const char *sender;
55 /* const char *dsn_envid;
58 /* void (*callback)(int status, char *context);
61 /* void adefer_warn(flags, queue, id, encoding, sender,
62 /* dsn_envid, dsn_ret, callback, context)
66 /* const char *encoding;
67 /* const char *sender;
68 /* const char *dsn_envid;
70 /* void (*callback)(int status, char *context);
73 /* This module implements an asynchronous interface to the
74 /* bounce/defer service for submitting sender notifications
75 /* without waiting for completion of the request.
77 /* abounce_flush() bounces the specified message to
78 /* the specified sender, including the bounce log that was
79 /* built with bounce_append().
81 /* abounce_flush_verp() is like abounce_flush() but sends
82 /* one VERP style notification per undeliverable recipient.
84 /* adefer_flush() bounces the specified message to
85 /* the specified sender, including the defer log that was
86 /* built with defer_append().
87 /* adefer_flush() requests that the deferred recipients are deleted
88 /* from the original queue file.
90 /* adefer_flush_verp() is like adefer_flush() but sends
91 /* one VERP style notification per undeliverable recipient.
93 /* adefer_warn() sends a "mail is delayed" notification to
94 /* the specified sender, including the defer log that was
95 /* built with defer_append().
99 /* The bitwise OR of zero or more of the following (specify
100 /* BOUNCE_FLAG_NONE to request no special processing):
102 /* .IP BOUNCE_FLAG_CLEAN
103 /* Delete the bounce log in case of an error (as in: pretend
104 /* that we never even tried to bounce this message).
105 /* .IP BOUNCE_FLAG_DELRCPT
106 /* When specified with a flush operation, request that
107 /* recipients be deleted from the queue file.
109 /* Note: the bounce daemon ignores this request when the
110 /* recipient queue file offset is <= 0.
111 /* .IP BOUNCE_FLAG_COPY
112 /* Request that a postmaster copy is sent.
115 /* The message queue name of the original message file.
117 /* The message queue id if the original message file. The bounce log
118 /* file has the same name as the original message file.
120 /* The body content encoding: MAIL_ATTR_ENC_{7BIT,8BIT,NONE}.
122 /* The sender envelope address.
124 /* Optional DSN envelope ID.
126 /* Optional DSN return full/headers option.
128 /* VERP delimiter characters.
130 /* Name of a routine that receives the notification status as
131 /* documented for bounce_flush() or defer_flush().
133 /* Application-specific context that is passed through to the
134 /* callback routine. Use proper casts or the world will come
137 /* In case of success, these functions log the action, and return a
138 /* zero result via the callback routine. Otherwise, the functions
139 /* return a non-zero result via the callback routine, and when
140 /* BOUNCE_FLAG_CLEAN is disabled, log that message delivery is deferred.
144 /* The Secure Mailer license must be distributed with this software.
147 /* IBM T.J. Watson Research
149 /* Yorktown Heights, NY 10598, USA
152 /* System library. */
154 #include <sys_defs.h>
156 /* Utility library. */
159 #include <mymalloc.h>
163 /* Global library. */
165 #include <mail_params.h>
166 #include <mail_proto.h>
169 /* Application-specific. */
172 * Each bounce/defer flush/warn request is implemented by sending the
173 * request to the bounce/defer server, and by creating a pseudo thread that
174 * suspends itself until the server replies (or dies). Upon wakeup, the
175 * pseudo thread delivers the request completion status to the application
176 * and destroys itself. The structure below maintains all the necessary
177 * request state while the pseudo thread is suspended.
180 int command
; /* bounce request type */
181 int flags
; /* bounce options */
182 char *id
; /* queue ID for logging */
183 ABOUNCE_FN callback
; /* application callback */
184 char *context
; /* application context */
185 VSTREAM
*fp
; /* server I/O handle */
188 /* abounce_done - deliver status to application and clean up pseudo thread */
190 static void abounce_done(ABOUNCE
*ap
, int status
)
192 (void) vstream_fclose(ap
->fp
);
193 if (status
!= 0 && (ap
->flags
& BOUNCE_FLAG_CLEAN
) == 0)
194 msg_info("%s: status=deferred (%s failed)", ap
->id
,
195 ap
->command
== BOUNCE_CMD_FLUSH
? "bounce" :
196 ap
->command
== BOUNCE_CMD_WARN
? "delay warning" :
198 ap
->callback(status
, ap
->context
);
203 /* abounce_event - resume pseudo thread after server reply event */
205 static void abounce_event(int unused_event
, char *context
)
207 ABOUNCE
*ap
= (ABOUNCE
*) context
;
210 event_disable_readwrite(vstream_fileno(ap
->fp
));
211 abounce_done(ap
, attr_scan(ap
->fp
, ATTR_FLAG_STRICT
,
212 ATTR_TYPE_INT
, MAIL_ATTR_STATUS
, &status
,
213 ATTR_TYPE_END
) == 1 ? status
: -1);
216 /* abounce_request_verp - suspend pseudo thread until server reply event */
218 static void abounce_request_verp(const char *class, const char *service
,
219 int command
, int flags
,
220 const char *queue
, const char *id
,
221 const char *encoding
,
223 const char *dsn_envid
,
232 * Save pseudo thread state. Connect to the server. Send the request and
233 * suspend the pseudo thread until the server replies (or dies).
235 ap
= (ABOUNCE
*) mymalloc(sizeof(*ap
));
236 ap
->command
= command
;
238 ap
->id
= mystrdup(id
);
239 ap
->callback
= callback
;
240 ap
->context
= context
;
241 ap
->fp
= mail_connect_wait(class, service
);
243 if (attr_print(ap
->fp
, ATTR_FLAG_NONE
,
244 ATTR_TYPE_INT
, MAIL_ATTR_NREQ
, command
,
245 ATTR_TYPE_INT
, MAIL_ATTR_FLAGS
, flags
,
246 ATTR_TYPE_STR
, MAIL_ATTR_QUEUE
, queue
,
247 ATTR_TYPE_STR
, MAIL_ATTR_QUEUEID
, id
,
248 ATTR_TYPE_STR
, MAIL_ATTR_ENCODING
, encoding
,
249 ATTR_TYPE_STR
, MAIL_ATTR_SENDER
, sender
,
250 ATTR_TYPE_STR
, MAIL_ATTR_DSN_ENVID
, dsn_envid
,
251 ATTR_TYPE_INT
, MAIL_ATTR_DSN_RET
, dsn_ret
,
252 ATTR_TYPE_STR
, MAIL_ATTR_VERPDL
, verp
,
254 && vstream_fflush(ap
->fp
) == 0) {
255 event_enable_read(vstream_fileno(ap
->fp
), abounce_event
, (char *) ap
);
257 abounce_done(ap
, -1);
261 /* abounce_flush_verp - asynchronous bounce flush */
263 void abounce_flush_verp(int flags
, const char *queue
, const char *id
,
264 const char *encoding
, const char *sender
,
265 const char *dsn_envid
, int dsn_ret
,
266 const char *verp
, ABOUNCE_FN callback
,
269 abounce_request_verp(MAIL_CLASS_PRIVATE
, var_bounce_service
,
270 BOUNCE_CMD_VERP
, flags
, queue
, id
, encoding
,
271 sender
, dsn_envid
, dsn_ret
, verp
, callback
, context
);
274 /* adefer_flush_verp - asynchronous defer flush */
276 void adefer_flush_verp(int flags
, const char *queue
, const char *id
,
277 const char *encoding
, const char *sender
,
278 const char *dsn_envid
, int dsn_ret
,
279 const char *verp
, ABOUNCE_FN callback
,
282 flags
|= BOUNCE_FLAG_DELRCPT
;
283 abounce_request_verp(MAIL_CLASS_PRIVATE
, var_defer_service
,
284 BOUNCE_CMD_VERP
, flags
, queue
, id
, encoding
,
285 sender
, dsn_envid
, dsn_ret
, verp
, callback
, context
);
288 /* abounce_request - suspend pseudo thread until server reply event */
290 static void abounce_request(const char *class, const char *service
,
291 int command
, int flags
,
292 const char *queue
, const char *id
,
293 const char *encoding
, const char *sender
,
294 const char *dsn_envid
, int dsn_ret
,
295 ABOUNCE_FN callback
, char *context
)
300 * Save pseudo thread state. Connect to the server. Send the request and
301 * suspend the pseudo thread until the server replies (or dies).
303 ap
= (ABOUNCE
*) mymalloc(sizeof(*ap
));
304 ap
->command
= command
;
306 ap
->id
= mystrdup(id
);
307 ap
->callback
= callback
;
308 ap
->context
= context
;
309 ap
->fp
= mail_connect_wait(class, service
);
311 if (attr_print(ap
->fp
, ATTR_FLAG_NONE
,
312 ATTR_TYPE_INT
, MAIL_ATTR_NREQ
, command
,
313 ATTR_TYPE_INT
, MAIL_ATTR_FLAGS
, flags
,
314 ATTR_TYPE_STR
, MAIL_ATTR_QUEUE
, queue
,
315 ATTR_TYPE_STR
, MAIL_ATTR_QUEUEID
, id
,
316 ATTR_TYPE_STR
, MAIL_ATTR_ENCODING
, encoding
,
317 ATTR_TYPE_STR
, MAIL_ATTR_SENDER
, sender
,
318 ATTR_TYPE_STR
, MAIL_ATTR_DSN_ENVID
, dsn_envid
,
319 ATTR_TYPE_INT
, MAIL_ATTR_DSN_RET
, dsn_ret
,
321 && vstream_fflush(ap
->fp
) == 0) {
322 event_enable_read(vstream_fileno(ap
->fp
), abounce_event
, (char *) ap
);
324 abounce_done(ap
, -1);
328 /* abounce_flush - asynchronous bounce flush */
330 void abounce_flush(int flags
, const char *queue
, const char *id
,
331 const char *encoding
, const char *sender
,
332 const char *dsn_envid
, int dsn_ret
,
333 ABOUNCE_FN callback
, char *context
)
335 abounce_request(MAIL_CLASS_PRIVATE
, var_bounce_service
, BOUNCE_CMD_FLUSH
,
336 flags
, queue
, id
, encoding
, sender
, dsn_envid
, dsn_ret
,
340 /* adefer_flush - asynchronous defer flush */
342 void adefer_flush(int flags
, const char *queue
, const char *id
,
343 const char *encoding
, const char *sender
,
344 const char *dsn_envid
, int dsn_ret
,
345 ABOUNCE_FN callback
, char *context
)
347 flags
|= BOUNCE_FLAG_DELRCPT
;
348 abounce_request(MAIL_CLASS_PRIVATE
, var_defer_service
, BOUNCE_CMD_FLUSH
,
349 flags
, queue
, id
, encoding
, sender
, dsn_envid
, dsn_ret
,
353 /* adefer_warn - send copy of defer log to sender as warning bounce */
355 void adefer_warn(int flags
, const char *queue
, const char *id
,
356 const char *encoding
, const char *sender
,
357 const char *dsn_envid
, int dsn_ret
,
358 ABOUNCE_FN callback
, char *context
)
360 abounce_request(MAIL_CLASS_PRIVATE
, var_defer_service
, BOUNCE_CMD_WARN
,
361 flags
, queue
, id
, encoding
, sender
, dsn_envid
, dsn_ret
,