示例#1
0
static void qmgr_active_done_3_generic(QMGR_MESSAGE *message)
{
    const char *myname = "qmgr_active_done_3_generic";
    int     delay;

    /*
     * Some recipients need to be tried again. Move the queue file time
     * stamps into the future by the amount of time that the message is
     * delayed, and move the message to the deferred queue. Impose minimal
     * and maximal backoff times.
     * 
     * Since we look at actual time in queue, not time since last delivery
     * attempt, backoff times will be distributed. However, we can still see
     * spikes in delivery activity because the interval between deferred
     * queue scans is finite.
     */
    if (message->flags) {
	if (message->create_time > 0) {
	    delay = event_time() - message->create_time;
	    if (delay > var_max_backoff_time)
		delay = var_max_backoff_time;
	    if (delay < var_min_backoff_time)
		delay = var_min_backoff_time;
	} else {
	    delay = var_min_backoff_time;
	}
	qmgr_active_defer(message->queue_name, message->queue_id,
			  MAIL_QUEUE_DEFERRED, delay);
    }

    /*
     * All recipients done. Remove the queue file.
     */
    else {
	if (mail_queue_remove(message->queue_name, message->queue_id)) {
	    if (errno != ENOENT)
		msg_fatal("%s: remove %s from %s: %m", myname,
			  message->queue_id, message->queue_name);
	    msg_warn("%s: remove %s from %s: %m", myname,
		     message->queue_id, message->queue_name);
	} else {
	    /* Same format as logged by postsuper. */
	    msg_info("%s: removed", message->queue_id);
	}
    }

    /*
     * Finally, delete the in-core message structure.
     */
    qmgr_message_free(message);
}
示例#2
0
QMGR_MESSAGE *qmgr_message_alloc(const char *queue_name, const char *queue_id,
				         int qflags, mode_t mode)
{
    const char *myname = "qmgr_message_alloc";
    QMGR_MESSAGE *message;

    if (msg_verbose)
	msg_info("%s: %s %s", myname, queue_name, queue_id);

    /*
     * Create an in-core message structure.
     */
    message = qmgr_message_create(queue_name, queue_id, qflags);

    /*
     * Extract message envelope information: time of arrival, sender address,
     * recipient addresses. Skip files with malformed envelope information.
     */
#define QMGR_LOCK_MODE (MYFLOCK_OP_EXCLUSIVE | MYFLOCK_OP_NOWAIT)

    if (qmgr_message_open(message) < 0) {
	qmgr_message_free(message);
	return (0);
    }
    if (myflock(vstream_fileno(message->fp), INTERNAL_LOCK, QMGR_LOCK_MODE) < 0) {
	msg_info("%s: skipped, still being delivered", queue_id);
	qmgr_message_close(message);
	qmgr_message_free(message);
	return (QMGR_MESSAGE_LOCKED);
    }
    if (qmgr_message_read(message) < 0) {
	qmgr_message_close(message);
	qmgr_message_free(message);
	return (0);
    } else {

	/*
	 * We have validated the queue file content, so it is safe to modify
	 * the file properties now.
	 */
	if (mode != 0 && fchmod(vstream_fileno(message->fp), mode) < 0)
	    msg_fatal("fchmod %s: %m", VSTREAM_PATH(message->fp));

	/*
	 * Reset the defer log. This code should not be here, but we must
	 * reset the defer log *after* acquiring the exclusive lock on the
	 * queue file and *before* resolving new recipients. Since all those
	 * operations are encapsulated so nicely by this routine, the defer
	 * log reset has to be done here as well.
	 * 
	 * Note: it is safe to remove the defer logfile from a previous queue
	 * run of this queue file, because the defer log contains information
	 * about recipients that still exist in this queue file.
	 */
	if (mail_queue_remove(MAIL_QUEUE_DEFER, queue_id) && errno != ENOENT)
	    msg_fatal("%s: %s: remove %s %s: %m", myname,
		      queue_id, MAIL_QUEUE_DEFER, queue_id);
	qmgr_message_sort(message);
	qmgr_message_resolve(message);
	qmgr_message_sort(message);
	qmgr_message_assign(message);
	qmgr_message_close(message);
	if (message->rcpt_offset == 0)
	    qmgr_message_move_limits(message);
	return (message);
    }
}
示例#3
0
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);
}
示例#4
0
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);
}