int qmgr_active_feed(QMGR_SCAN *scan_info, const char *queue_id) { const char *myname = "qmgr_active_feed"; QMGR_MESSAGE *message; struct stat st; const char *path; if (strcmp(scan_info->queue, MAIL_QUEUE_ACTIVE) == 0) msg_panic("%s: bad queue %s", myname, scan_info->queue); if (msg_verbose) msg_info("%s: queue %s", myname, scan_info->queue); /* * Make sure this is something we are willing to open. */ if (mail_open_ok(scan_info->queue, queue_id, &st, &path) == MAIL_OPEN_NO) return (0); if (msg_verbose) msg_info("%s: %s", myname, path); /* * Skip files that have time stamps into the future. They need to cool * down. Incoming and deferred files can have future time stamps. */ if ((scan_info->flags & QMGR_SCAN_ALL) == 0 && st.st_mtime > time((time_t *) 0) + 1) { if (msg_verbose) msg_info("%s: skip %s (%ld seconds)", myname, queue_id, (long) (st.st_mtime - event_time())); return (0); } /* * Move the message to the active queue. File access errors are fatal. */ if (mail_queue_rename(queue_id, scan_info->queue, MAIL_QUEUE_ACTIVE)) { if (errno != ENOENT) msg_fatal("%s: %s: rename from %s to %s: %m", myname, queue_id, scan_info->queue, MAIL_QUEUE_ACTIVE); msg_warn("%s: %s: rename from %s to %s: %m", myname, queue_id, scan_info->queue, MAIL_QUEUE_ACTIVE); return (0); } /* * Extract envelope information: sender and recipients. At this point, * mail addresses have been processed by the cleanup service so they * should be in canonical form. Generate requests to deliver this * message. * * Throwing away queue files seems bad, especially when they made it this * far into the mail system. Therefore we save bad files to a separate * directory for further inspection. * * After queue manager restart it is possible that a queue file is still * being delivered. In that case (the file is locked), defer delivery by * a minimal amount of time. */ #define QMGR_FLUSH_AFTER (QMGR_FLUSH_EACH | QMGR_FLUSH_DFXP) if ((message = qmgr_message_alloc(MAIL_QUEUE_ACTIVE, queue_id, (st.st_mode & MAIL_QUEUE_STAT_UNTHROTTLE) ? scan_info->flags | QMGR_FLUSH_AFTER : scan_info->flags, (st.st_mode & MAIL_QUEUE_STAT_UNTHROTTLE) ? st.st_mode & ~MAIL_QUEUE_STAT_UNTHROTTLE : 0)) == 0) { qmgr_active_corrupt(queue_id); return (0); } else if (message == QMGR_MESSAGE_LOCKED) { qmgr_active_defer(MAIL_QUEUE_ACTIVE, queue_id, MAIL_QUEUE_INCOMING, 60); return (0); } else { /* * Special case if all recipients were already delivered. Send any * bounces and clean up. */ if (message->refcount == 0) qmgr_active_done(message); return (1); } }
static void qmgr_active_done_2_generic(QMGR_MESSAGE *message) { const char *path; struct stat st; /* * A delivery agent marks a queue file as corrupt by changing its * attributes, and by pretending that delivery was deferred. */ if (message->flags && mail_open_ok(MAIL_QUEUE_ACTIVE, message->queue_id, &st, &path) == MAIL_OPEN_NO) { qmgr_active_corrupt(message->queue_id); qmgr_message_free(message); return; } /* * If we did not read all recipients from this file, go read some more, * but remember whether some recipients have to be tried again. * * Throwing away queue files seems bad, especially when they made it this * far into the mail system. Therefore we save bad files to a separate * directory for further inspection by a human being. */ if (message->rcpt_offset > 0) { if (qmgr_message_realloc(message) == 0) { qmgr_active_corrupt(message->queue_id); qmgr_message_free(message); } else { if (message->refcount == 0) qmgr_active_done(message); /* recurse for consistency */ } return; } /* * XXX With multi-recipient mail, some recipients may have NOTIFY=SUCCESS * and others not. Depending on what subset of recipients are delivered, * a trace file may or may not be created. Even when the last partial * delivery attempt had no NOTIFY=SUCCESS recipients, a trace file may * still exist from a previous partial delivery attempt. So as long as * any recipient has NOTIFY=SUCCESS we have to always look for the trace * file and be prepared for the file not to exist. * * See also comments in bounce/bounce_notify_util.c. */ if ((message->tflags & (DEL_REQ_FLAG_USR_VRFY | DEL_REQ_FLAG_RECORD)) || (message->rflags & QMGR_READ_FLAG_NOTIFY_SUCCESS)) { atrace_flush(message->tflags, message->queue_name, message->queue_id, message->encoding, message->sender, message->dsn_envid, message->dsn_ret, qmgr_active_done_25_trace_flush, (char *) message); return; } /* * Asynchronous processing does not reach this point. */ qmgr_active_done_25_generic(message); }
static void qmgr_active_done_2_generic(QMGR_MESSAGE *message) { char *myname = "qmgr_active_done_2_generic"; const char *path; struct stat st; int status; /* * A delivery agent marks a queue file as corrupt by changing its * attributes, and by pretending that delivery was deferred. */ if (message->flags && mail_open_ok(MAIL_QUEUE_ACTIVE, message->queue_id, &st, &path) == MAIL_OPEN_NO) { qmgr_active_corrupt(message->queue_id); qmgr_message_free(message); return; } /* * If we did not read all recipients from this file, go read some more, * but remember whether some recipients have to be tried again. * * Throwing away queue files seems bad, especially when they made it this * far into the mail system. Therefore we save bad files to a separate * directory for further inspection by a human being. */ if (message->rcpt_offset > 0) { if (qmgr_message_realloc(message) == 0) { qmgr_active_corrupt(message->queue_id); qmgr_message_free(message); } else { if (message->refcount == 0) qmgr_active_done(message); /* recurse for consistency */ } return; } /* * As a temporary implementation, synchronously inform the sender of * trace information. This will block for 10 seconds when the qmgr FIFO * is full. */ if (message->tflags & (DEL_REQ_FLAG_EXPAND | DEL_REQ_FLAG_RECORD)) { status = trace_flush(message->tflags, message->queue_name, message->queue_id, message->encoding, message->sender); if (status == 0 && message->tflags_offset) qmgr_message_kill_record(message, message->tflags_offset); message->flags |= status; } /* * If we get to this point we have tried all recipients for this message. * If the message is too old, try to bounce it. * * Bounces are sent asynchronously to avoid stalling while the cleanup * daemon waits for the qmgr to accept the "new mail" trigger. */ if (message->flags) { if (event_time() >= message->arrival_time + (*message->sender ? var_max_queue_time : var_dsn_queue_time)) { msg_info("%s: from=<%s>, status=expired, returned to sender", message->queue_id, message->sender); if (message->verp_delims == 0 || var_verp_bounce_off) adefer_flush(BOUNCE_FLAG_KEEP, message->queue_name, message->queue_id, message->encoding, message->errors_to, qmgr_active_done_3_defer_flush, (char *) message); else adefer_flush_verp(BOUNCE_FLAG_KEEP, message->queue_name, message->queue_id, message->encoding, message->errors_to, message->verp_delims, qmgr_active_done_3_defer_flush, (char *) message); return; } else if (message->warn_time > 0 && event_time() > message->warn_time) { if (msg_verbose) msg_info("%s: sending defer warning for %s", myname, message->queue_id); adefer_warn(BOUNCE_FLAG_KEEP, message->queue_name, message->queue_id, message->encoding, message->errors_to, qmgr_active_done_3_defer_warn, (char *) message); return; } } /* * Asynchronous processing does not reach this point. */ qmgr_active_done_3_generic(message); }