1/*++
2/* NAME
3/*	qmgr_defer
4/* SUMMARY
5/*	deal with mail that must be delivered later
6/* SYNOPSIS
7/*	#include "qmgr.h"
8/*
9/*	void	qmgr_defer_recipient(message, recipient, dsn)
10/*	QMGR_MESSAGE *message;
11/*	RECIPIENT *recipient;
12/*	DSN	*dsn;
13/*
14/*	void	qmgr_defer_todo(queue, dsn)
15/*	QMGR_QUEUE *queue;
16/*	DSN	*dsn;
17/*
18/*	void	qmgr_defer_transport(transport, dsn)
19/*	QMGR_TRANSPORT *transport;
20/*	DSN	*dsn;
21/* DESCRIPTION
22/*	qmgr_defer_recipient() defers delivery of the named message to
23/*	the named recipient. It updates the message structure and writes
24/*	a log entry.
25/*
26/*	qmgr_defer_todo() iterates over all "todo" deliveries queued for
27/*	the named site, and calls qmgr_defer_recipient() for each recipient
28/*	found.  Side effects caused by qmgr_entry_done(), qmgr_queue_done(),
29/*	and by qmgr_active_done(): in-core queue entries will disappear,
30/*	in-core queues may disappear, in-core and on-disk messages may
31/*	disappear, bounces may be sent, new in-core queues, queue entries
32/*	and recipients may appear.
33/*
34/*	qmgr_defer_transport() calls qmgr_defer_todo() for each queue
35/*	that depends on the named transport. See there for side effects.
36/*
37/*	Arguments:
38/* .IP recipient
39/*	A recipient address; used for logging purposes, and for updating
40/*	the message-specific \fIdefer\fR log.
41/* .IP queue
42/*	Specifies a queue with delivery requests for a specific next-hop
43/*	host (or local user).
44/* .IP transport
45/*	Specifies a message delivery transport.
46/* .IP dsn
47/*	See dsn(3).
48/* BUGS
49/*	The side effects of calling this routine are quite dramatic.
50/* DIAGNOSTICS
51/*	Panic: consistency check failure. Fatal: out of memory.
52/* LICENSE
53/* .ad
54/* .fi
55/*	The Secure Mailer license must be distributed with this software.
56/* AUTHOR(S)
57/*	Wietse Venema
58/*	IBM T.J. Watson Research
59/*	P.O. Box 704
60/*	Yorktown Heights, NY 10598, USA
61/*--*/
62
63/* System library. */
64
65#include <sys_defs.h>
66
67/* Utility library. */
68
69#include <msg.h>
70#include <vstream.h>
71
72/* Global library. */
73
74#include <mail_proto.h>
75#include <defer.h>
76
77/* Application-specific. */
78
79#include "qmgr.h"
80
81/* qmgr_defer_transport - defer todo entries for named transport */
82
83void    qmgr_defer_transport(QMGR_TRANSPORT *transport, DSN *dsn)
84{
85    QMGR_QUEUE *queue;
86    QMGR_QUEUE *next;
87
88    if (msg_verbose)
89	msg_info("defer transport %s: %s %s",
90		 transport->name, dsn->status, dsn->reason);
91
92    /*
93     * Proceed carefully. Queues may disappear as a side effect.
94     */
95    for (queue = transport->queue_list.next; queue; queue = next) {
96	next = queue->peers.next;
97	qmgr_defer_todo(queue, dsn);
98    }
99}
100
101/* qmgr_defer_todo - defer all todo queue entries for specific site */
102
103void    qmgr_defer_todo(QMGR_QUEUE *queue, DSN *dsn)
104{
105    QMGR_ENTRY *entry;
106    QMGR_ENTRY *next;
107    QMGR_MESSAGE *message;
108    RECIPIENT *recipient;
109    int     nrcpt;
110    QMGR_QUEUE *retry_queue;
111
112    /*
113     * Sanity checks.
114     */
115    if (msg_verbose)
116	msg_info("defer site %s: %s %s",
117		 queue->name, dsn->status, dsn->reason);
118
119    /*
120     * See if we can redirect the deliveries to the retry(8) delivery agent,
121     * so that they can be handled asynchronously. If the retry(8) service is
122     * unavailable, use the synchronous defer(8) server. With a large todo
123     * queue, this blocks the queue manager for a significant time.
124     */
125    retry_queue = qmgr_error_queue(MAIL_SERVICE_RETRY, dsn);
126
127    /*
128     * Proceed carefully. Queue entries may disappear as a side effect.
129     */
130    for (entry = queue->todo.next; entry != 0; entry = next) {
131	next = entry->peers.next;
132	if (retry_queue != 0) {
133	    qmgr_entry_move_todo(retry_queue, entry);
134	    continue;
135	}
136	message = entry->message;
137	for (nrcpt = 0; nrcpt < entry->rcpt_list.len; nrcpt++) {
138	    recipient = entry->rcpt_list.info + nrcpt;
139	    qmgr_defer_recipient(message, recipient, dsn);
140	}
141	qmgr_entry_done(entry, QMGR_QUEUE_TODO);
142    }
143}
144
145/* qmgr_defer_recipient - defer delivery of specific recipient */
146
147void    qmgr_defer_recipient(QMGR_MESSAGE *message, RECIPIENT *recipient,
148			             DSN *dsn)
149{
150    MSG_STATS stats;
151
152    /*
153     * Update the message structure and log the message disposition.
154     */
155    message->flags |= defer_append(message->tflags, message->queue_id,
156				 QMGR_MSG_STATS(&stats, message), recipient,
157				   "none", dsn);
158}
159