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