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/*	Preemptive scheduler enhancements:
63/*	Patrik Rak
64/*	Modra 6
65/*	155 00, Prague, Czech Republic
66/*--*/
67
68/* System library. */
69
70#include <sys_defs.h>
71
72/* Utility library. */
73
74#include <msg.h>
75#include <vstream.h>
76
77/* Global library. */
78
79#include <mail_proto.h>
80#include <defer.h>
81
82/* Application-specific. */
83
84#include "qmgr.h"
85
86/* qmgr_defer_transport - defer todo entries for named transport */
87
88void    qmgr_defer_transport(QMGR_TRANSPORT *transport, DSN *dsn)
89{
90    QMGR_QUEUE *queue;
91    QMGR_QUEUE *next;
92
93    if (msg_verbose)
94	msg_info("defer transport %s: %s %s",
95		 transport->name, dsn->status, dsn->reason);
96
97    /*
98     * Proceed carefully. Queues may disappear as a side effect.
99     */
100    for (queue = transport->queue_list.next; queue; queue = next) {
101	next = queue->peers.next;
102	qmgr_defer_todo(queue, dsn);
103    }
104}
105
106/* qmgr_defer_todo - defer all todo queue entries for specific site */
107
108void    qmgr_defer_todo(QMGR_QUEUE *queue, DSN *dsn)
109{
110    QMGR_ENTRY *entry;
111    QMGR_ENTRY *next;
112    QMGR_MESSAGE *message;
113    RECIPIENT *recipient;
114    int     nrcpt;
115    QMGR_QUEUE *retry_queue;
116
117    /*
118     * Sanity checks.
119     */
120    if (msg_verbose)
121	msg_info("defer site %s: %s %s",
122		 queue->name, dsn->status, dsn->reason);
123
124    /*
125     * See if we can redirect the deliveries to the retry(8) delivery agent,
126     * so that they can be handled asynchronously. If the retry(8) service is
127     * unavailable, use the synchronous defer(8) server. With a large todo
128     * queue, this blocks the queue manager for a significant time.
129     */
130    retry_queue = qmgr_error_queue(MAIL_SERVICE_RETRY, dsn);
131
132    /*
133     * Proceed carefully. Queue entries may disappear as a side effect.
134     */
135    for (entry = queue->todo.next; entry != 0; entry = next) {
136	next = entry->queue_peers.next;
137	if (retry_queue != 0) {
138	    qmgr_entry_move_todo(retry_queue, entry);
139	    continue;
140	}
141	message = entry->message;
142	for (nrcpt = 0; nrcpt < entry->rcpt_list.len; nrcpt++) {
143	    recipient = entry->rcpt_list.info + nrcpt;
144	    qmgr_defer_recipient(message, recipient, dsn);
145	}
146	qmgr_entry_done(entry, QMGR_QUEUE_TODO);
147    }
148}
149
150/* qmgr_defer_recipient - defer delivery of specific recipient */
151
152void    qmgr_defer_recipient(QMGR_MESSAGE *message, RECIPIENT *recipient,
153			             DSN *dsn)
154{
155    MSG_STATS stats;
156
157    /*
158     * Update the message structure and log the message disposition.
159     */
160    message->flags |= defer_append(message->tflags, message->queue_id,
161				 QMGR_MSG_STATS(&stats, message), recipient,
162				   "none", dsn);
163}
164