1/*++
2/* NAME
3/*	qmgr_scan 3
4/* SUMMARY
5/*	queue scanning
6/* SYNOPSIS
7/*	#include "qmgr.h"
8/*
9/*	QMGR_SCAN *qmgr_scan_create(queue_name)
10/*	const char *queue_name;
11/*
12/*	char	*qmgr_scan_next(scan_info)
13/*	QMGR_SCAN *scan_info;
14/*
15/*	void	qmgr_scan_request(scan_info, flags)
16/*	QMGR_SCAN *scan_info;
17/*	int	flags;
18/* DESCRIPTION
19/*	This module implements queue scans. A queue scan always runs
20/*	to completion, so that all files get a fair chance. The caller
21/*	can request that a queue scan be restarted once it completes.
22/*
23/*	qmgr_scan_create() creates a context for scanning the named queue,
24/*	but does not start a queue scan.
25/*
26/*	qmgr_scan_next() returns the base name of the next queue file.
27/*	A null pointer means that no file was found. qmgr_scan_next()
28/*	automagically restarts a queue scan when a scan request had
29/*	arrived while the scan was in progress.
30/*
31/*	qmgr_scan_request() records a request for the next queue scan. The
32/*	flags argument is the bit-wise OR of zero or more of the following,
33/*	unrecognized flags being ignored:
34/* .IP QMGR_FLUSH_ONCE
35/*	Forget state information about dead hosts or transports.
36/*	This request takes effect immediately.
37/* .IP QMGR_FLUSH_DFXP
38/*	Override the defer_transports setting. This takes effect
39/*	immediately when a queue scan is in progress, and affects
40/*	the next queue scan.
41/* .IP QMGR_SCAN_ALL
42/*	Ignore queue file time stamps. This takes effect immediately
43/*	when a queue scan is in progress, and affects the next queue
44/*	scan.
45/* .IP QMGR_SCAN_START
46/*	Start a queue scan when none is in progress, or restart the
47/*	current scan upon completion.
48/* DIAGNOSTICS
49/*	Fatal: out of memory.
50/*	Panic: interface violations, internal consistency errors.
51/* LICENSE
52/* .ad
53/* .fi
54/*	The Secure Mailer license must be distributed with this software.
55/* AUTHOR(S)
56/*	Wietse Venema
57/*	IBM T.J. Watson Research
58/*	P.O. Box 704
59/*	Yorktown Heights, NY 10598, USA
60/*--*/
61
62/* System library. */
63
64#include <sys_defs.h>
65
66/* Utility library. */
67
68#include <msg.h>
69#include <mymalloc.h>
70#include <scan_dir.h>
71
72/* Global library. */
73
74#include <mail_scan_dir.h>
75
76/* Application-specific. */
77
78#include "qmgr.h"
79
80/* qmgr_scan_start - start queue scan */
81
82static void qmgr_scan_start(QMGR_SCAN *scan_info)
83{
84    const char *myname = "qmgr_scan_start";
85
86    /*
87     * Sanity check.
88     */
89    if (scan_info->handle)
90	msg_panic("%s: %s queue scan in progress",
91		  myname, scan_info->queue);
92
93    /*
94     * Give the poor tester a clue.
95     */
96    if (msg_verbose)
97	msg_info("%s: %sstart %s queue scan",
98		 myname,
99		 scan_info->nflags & QMGR_SCAN_START ? "re" : "",
100		 scan_info->queue);
101
102    /*
103     * Start or restart the scan.
104     */
105    scan_info->flags = scan_info->nflags;
106    scan_info->nflags = 0;
107    scan_info->handle = scan_dir_open(scan_info->queue);
108}
109
110/* qmgr_scan_request - request for future scan */
111
112void    qmgr_scan_request(QMGR_SCAN *scan_info, int flags)
113{
114
115    /*
116     * Apply "forget all dead destinations" requests immediately. Throttle
117     * dead transports and queues at the earliest opportunity: preferably
118     * during an already ongoing queue scan, otherwise the throttling will
119     * have to wait until a "start scan" trigger arrives.
120     *
121     * The QMGR_FLUSH_ONCE request always comes with QMGR_FLUSH_DFXP, and
122     * sometimes it also comes with QMGR_SCAN_ALL. It becomes a completely
123     * different story when a flush request is encoded in file permissions.
124     */
125    if (flags & QMGR_FLUSH_ONCE)
126	qmgr_enable_all();
127
128    /*
129     * Apply "ignore time stamp" requests also towards the scan that is
130     * already in progress.
131     */
132    if (scan_info->handle != 0 && (flags & QMGR_SCAN_ALL))
133	scan_info->flags |= QMGR_SCAN_ALL;
134
135    /*
136     * Apply "override defer_transports" requests also towards the scan that
137     * is already in progress.
138     */
139    if (scan_info->handle != 0 && (flags & QMGR_FLUSH_DFXP))
140	scan_info->flags |= QMGR_FLUSH_DFXP;
141
142    /*
143     * If a scan is in progress, just record the request.
144     */
145    scan_info->nflags |= flags;
146    if (scan_info->handle == 0 && (flags & QMGR_SCAN_START) != 0) {
147	scan_info->nflags &= ~QMGR_SCAN_START;
148	qmgr_scan_start(scan_info);
149    }
150}
151
152/* qmgr_scan_next - look for next queue file */
153
154char   *qmgr_scan_next(QMGR_SCAN *scan_info)
155{
156    char   *path = 0;
157
158    /*
159     * Restart the scan if we reach the end and a queue scan request has
160     * arrived in the mean time.
161     */
162    if (scan_info->handle && (path = mail_scan_dir_next(scan_info->handle)) == 0) {
163	scan_info->handle = scan_dir_close(scan_info->handle);
164	if (msg_verbose && (scan_info->nflags & QMGR_SCAN_START) == 0)
165	    msg_info("done %s queue scan", scan_info->queue);
166    }
167    if (!scan_info->handle && (scan_info->nflags & QMGR_SCAN_START)) {
168	qmgr_scan_start(scan_info);
169	path = mail_scan_dir_next(scan_info->handle);
170    }
171    return (path);
172}
173
174/* qmgr_scan_create - create queue scan context */
175
176QMGR_SCAN *qmgr_scan_create(const char *queue)
177{
178    QMGR_SCAN *scan_info;
179
180    scan_info = (QMGR_SCAN *) mymalloc(sizeof(*scan_info));
181    scan_info->queue = mystrdup(queue);
182    scan_info->flags = scan_info->nflags = 0;
183    scan_info->handle = 0;
184    return (scan_info);
185}
186