xref: /netbsd-src/external/ibm-public/postfix/dist/src/global/abounce.c (revision 1b9578b8c2c1f848eeb16dabbfd7d1f0d9fdefbd)
1 /*	$NetBSD: abounce.c,v 1.1.1.1 2009/06/23 10:08:44 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	abounce 3
6 /* SUMMARY
7 /*	asynchronous bounce/defer service client
8 /* SYNOPSIS
9 /*	#include <abounce.h>
10 /*
11 /*	void	abounce_flush(flags, queue, id, encoding, sender,
12 /*				dsn_envid, dsn_ret, callback, context)
13 /*	int	flags;
14 /*	const char *queue;
15 /*	const char *id;
16 /*	const char *encoding;
17 /*	const char *sender;
18 /*	const char *dsn_envid;
19 /*	int	dsn_ret;
20 /*	void	(*callback)(int status, char *context);
21 /*	char	*context;
22 /*
23 /*	void	abounce_flush_verp(flags, queue, id, encoding, sender,
24 /*				dsn_envid, dsn_ret, verp, callback, context)
25 /*	int	flags;
26 /*	const char *queue;
27 /*	const char *id;
28 /*	const char *encoding;
29 /*	const char *sender;
30 /*	const char *dsn_envid;
31 /*	int	dsn_ret;
32 /*	const char *verp;
33 /*	void	(*callback)(int status, char *context);
34 /*	char	*context;
35 /*
36 /*	void	adefer_flush(flags, queue, id, encoding, sender,
37 /*				dsn_envid, dsn_ret, callback, context)
38 /*	int	flags;
39 /*	const char *queue;
40 /*	const char *id;
41 /*	const char *encoding;
42 /*	const char *sender;
43 /*	const char *dsn_envid;
44 /*	int	dsn_ret;
45 /*	void	(*callback)(int status, char *context);
46 /*	char	*context;
47 /*
48 /*	void	adefer_flush_verp(flags, queue, id, encoding, sender,
49 /*				dsn_envid, dsn_ret, verp, callback, context)
50 /*	int	flags;
51 /*	const char *queue;
52 /*	const char *id;
53 /*	const char *encoding;
54 /*	const char *sender;
55 /*	const char *dsn_envid;
56 /*	int	dsn_ret;
57 /*	const char *verp;
58 /*	void	(*callback)(int status, char *context);
59 /*	char	*context;
60 /*
61 /*	void	adefer_warn(flags, queue, id, encoding, sender,
62 /*				dsn_envid, dsn_ret, callback, context)
63 /*	int	flags;
64 /*	const char *queue;
65 /*	const char *id;
66 /*	const char *encoding;
67 /*	const char *sender;
68 /*	const char *dsn_envid;
69 /*	int	dsn_ret;
70 /*	void	(*callback)(int status, char *context);
71 /*	char	*context;
72 /* DESCRIPTION
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.
76 /*
77 /*	abounce_flush() bounces the specified message to
78 /*	the specified sender, including the bounce log that was
79 /*	built with bounce_append().
80 /*
81 /*	abounce_flush_verp() is like abounce_flush() but sends
82 /*	one VERP style notification per undeliverable recipient.
83 /*
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.
89 /*
90 /*	adefer_flush_verp() is like adefer_flush() but sends
91 /*	one VERP style notification per undeliverable recipient.
92 /*
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().
96 /*
97 /*	Arguments:
98 /* .IP flags
99 /*	The bitwise OR of zero or more of the following (specify
100 /*	BOUNCE_FLAG_NONE to request no special processing):
101 /* .RS
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.
108 /*
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.
113 /* .RE
114 /* .IP queue
115 /*	The message queue name of the original message file.
116 /* .IP id
117 /*	The message queue id if the original message file. The bounce log
118 /*	file has the same name as the original message file.
119 /* .IP encoding
120 /*	The body content encoding: MAIL_ATTR_ENC_{7BIT,8BIT,NONE}.
121 /* .IP sender
122 /*	The sender envelope address.
123 /* .IP dsn_envid
124 /*	Optional DSN envelope ID.
125 /* .IP ret
126 /*	Optional DSN return full/headers option.
127 /* .IP verp
128 /*	VERP delimiter characters.
129 /* .IP callback
130 /*	Name of a routine that receives the notification status as
131 /*	documented for bounce_flush() or defer_flush().
132 /* .IP context
133 /*	Application-specific context that is passed through to the
134 /*	callback routine. Use proper casts or the world will come
135 /*	to an end.
136 /* DIAGNOSTICS
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.
141 /* LICENSE
142 /* .ad
143 /* .fi
144 /*	The Secure Mailer license must be distributed with this software.
145 /* AUTHOR(S)
146 /*	Wietse Venema
147 /*	IBM T.J. Watson Research
148 /*	P.O. Box 704
149 /*	Yorktown Heights, NY 10598, USA
150 /*--*/
151 
152 /* System library. */
153 
154 #include <sys_defs.h>
155 
156 /* Utility library. */
157 
158 #include <msg.h>
159 #include <mymalloc.h>
160 #include <events.h>
161 #include <vstream.h>
162 
163 /* Global library. */
164 
165 #include <mail_params.h>
166 #include <mail_proto.h>
167 #include <abounce.h>
168 
169 /* Application-specific. */
170 
171  /*
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.
178   */
179 typedef struct {
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 */
186 } ABOUNCE;
187 
188 /* abounce_done - deliver status to application and clean up pseudo thread */
189 
190 static void abounce_done(ABOUNCE *ap, int status)
191 {
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" :
197 		 "whatever");
198     ap->callback(status, ap->context);
199     myfree(ap->id);
200     myfree((char *) ap);
201 }
202 
203 /* abounce_event - resume pseudo thread after server reply event */
204 
205 static void abounce_event(int unused_event, char *context)
206 {
207     ABOUNCE *ap = (ABOUNCE *) context;
208     int     status;
209 
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);
214 }
215 
216 /* abounce_request_verp - suspend pseudo thread until server reply event */
217 
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,
222 				         const char *sender,
223 				         const char *dsn_envid,
224 				         int dsn_ret,
225 					 const char *verp,
226 				         ABOUNCE_FN callback,
227 				         char *context)
228 {
229     ABOUNCE *ap;
230 
231     /*
232      * Save pseudo thread state. Connect to the server. Send the request and
233      * suspend the pseudo thread until the server replies (or dies).
234      */
235     ap = (ABOUNCE *) mymalloc(sizeof(*ap));
236     ap->command = command;
237     ap->flags = flags;
238     ap->id = mystrdup(id);
239     ap->callback = callback;
240     ap->context = context;
241     ap->fp = mail_connect_wait(class, service);
242 
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,
253 		   ATTR_TYPE_END) == 0
254 	&& vstream_fflush(ap->fp) == 0) {
255 	event_enable_read(vstream_fileno(ap->fp), abounce_event, (char *) ap);
256     } else {
257 	abounce_done(ap, -1);
258     }
259 }
260 
261 /* abounce_flush_verp - asynchronous bounce flush */
262 
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,
267 			           char *context)
268 {
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);
272 }
273 
274 /* adefer_flush_verp - asynchronous defer flush */
275 
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,
280 			          char *context)
281 {
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);
286 }
287 
288 /* abounce_request - suspend pseudo thread until server reply event */
289 
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)
296 {
297     ABOUNCE *ap;
298 
299     /*
300      * Save pseudo thread state. Connect to the server. Send the request and
301      * suspend the pseudo thread until the server replies (or dies).
302      */
303     ap = (ABOUNCE *) mymalloc(sizeof(*ap));
304     ap->command = command;
305     ap->flags = flags;
306     ap->id = mystrdup(id);
307     ap->callback = callback;
308     ap->context = context;
309     ap->fp = mail_connect_wait(class, service);
310 
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,
320 		   ATTR_TYPE_END) == 0
321 	&& vstream_fflush(ap->fp) == 0) {
322 	event_enable_read(vstream_fileno(ap->fp), abounce_event, (char *) ap);
323     } else {
324 	abounce_done(ap, -1);
325     }
326 }
327 
328 /* abounce_flush - asynchronous bounce flush */
329 
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)
334 {
335     abounce_request(MAIL_CLASS_PRIVATE, var_bounce_service, BOUNCE_CMD_FLUSH,
336 		    flags, queue, id, encoding, sender, dsn_envid, dsn_ret,
337 		    callback, context);
338 }
339 
340 /* adefer_flush - asynchronous defer flush */
341 
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)
346 {
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,
350 		    callback, context);
351 }
352 
353 /* adefer_warn - send copy of defer log to sender as warning bounce */
354 
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)
359 {
360     abounce_request(MAIL_CLASS_PRIVATE, var_defer_service, BOUNCE_CMD_WARN,
361 		    flags, queue, id, encoding, sender, dsn_envid, dsn_ret,
362 		    callback, context);
363 }
364