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