xref: /netbsd-src/external/ibm-public/postfix/dist/src/global/been_here.c (revision 67b9b338a7386232ac596b5fd0cd5a9cc8a03c71)
1 /*	$NetBSD: been_here.c,v 1.4 2022/10/08 16:12:45 christos Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	been_here 3
6 /* SUMMARY
7 /*	detect repeated occurrence of string
8 /* SYNOPSIS
9 /*	#include <been_here.h>
10 /*
11 /*	BH_TABLE *been_here_init(size, flags)
12 /*	int	size;
13 /*	int	flags;
14 /*
15 /*	int	been_here_fixed(dup_filter, string)
16 /*	BH_TABLE *dup_filter;
17 /*	char	*string;
18 /*
19 /*	int	been_here(dup_filter, format, ...)
20 /*	BH_TABLE *dup_filter;
21 /*	char	*format;
22 /*
23 /*	int	been_here_check_fixed(dup_filter, string)
24 /*	BH_TABLE *dup_filter;
25 /*	char	*string;
26 /*
27 /*	int	been_here_check(dup_filter, format, ...)
28 /*	BH_TABLE *dup_filter;
29 /*	char	*format;
30 /*
31 /*	int	been_here_drop_fixed(dup_filter, string)
32 /*	BH_TABLE *dup_filter;
33 /*	char	*string;
34 /*
35 /*	int	been_here_drop(dup_filter, format, ...)
36 /*	BH_TABLE *dup_filter;
37 /*	char	*format;
38 /*
39 /*	void	been_here_free(dup_filter)
40 /*	BH_TABLE *dup_filter;
41 /* DESCRIPTION
42 /*	This module implements a simple filter to detect repeated
43 /*	occurrences of character strings.
44 /*
45 /*	been_here_init() creates an empty duplicate filter.
46 /*
47 /*	been_here_fixed() looks up a fixed string in the given table, and
48 /*	makes an entry in the table if the string was not found. The result
49 /*	is non-zero (true) if the string was found, zero (false) otherwise.
50 /*
51 /*	been_here() formats its arguments, looks up the result in the
52 /*	given table, and makes an entry in the table if the string was
53 /*	not found. The result is non-zero (true) if the formatted result was
54 /*	found, zero (false) otherwise.
55 /*
56 /*	been_here_check_fixed() and been_here_check() are similar
57 /*	but do not update the duplicate filter.
58 /*
59 /*	been_here_drop_fixed() looks up a fixed string in the given
60 /*	table, and deletes the entry if the string was found. The
61 /*	result is non-zero (true) if the string was found, zero
62 /*	(false) otherwise.
63 /*
64 /*	been_here_drop() formats its arguments, looks up the result
65 /*	in the given table, and removes the entry if the formatted
66 /*	result was found. The result is non-zero (true) if the
67 /*	formatted result was found, zero (false) otherwise.
68 /*
69 /*	been_here_free() releases storage for a duplicate filter.
70 /*
71 /*	Arguments:
72 /* .IP size
73 /*	Upper bound on the table size; at most \fIsize\fR strings will
74 /*	be remembered.  Specify BH_BOUND_NONE to disable the upper bound.
75 /* .IP flags
76 /*	Requests for special processing. Specify the bitwise OR of zero
77 /*	or more flags:
78 /* .RS
79 /* .IP BH_FLAG_FOLD
80 /*	Enable case-insensitive lookup.
81 /* .IP BH_FLAG_NONE
82 /*	A manifest constant that requests no special processing.
83 /* .RE
84 /* .IP dup_filter
85 /*	The table with remembered names
86 /* .IP string
87 /*	Fixed search string.
88 /* .IP format
89 /*	Format for building the search string.
90 /* LICENSE
91 /* .ad
92 /* .fi
93 /*	The Secure Mailer license must be distributed with this software.
94 /* AUTHOR(S)
95 /*	Wietse Venema
96 /*	IBM T.J. Watson Research
97 /*	P.O. Box 704
98 /*	Yorktown Heights, NY 10598, USA
99 /*
100 /*	Wietse Venema
101 /*	Google, Inc.
102 /*	111 8th Avenue
103 /*	New York, NY 10011, USA
104 /*--*/
105 
106 /* System library. */
107 
108 #include "sys_defs.h"
109 #include <stdlib.h>			/* 44BSD stdarg.h uses abort() */
110 #include <stdarg.h>
111 
112 /* Utility library. */
113 
114 #include <msg.h>
115 #include <mymalloc.h>
116 #include <htable.h>
117 #include <vstring.h>
118 #include <stringops.h>
119 
120 /* Global library. */
121 
122 #include "been_here.h"
123 
124 #define STR(x)	vstring_str(x)
125 
126 /* been_here_init - initialize duplicate filter */
127 
been_here_init(int limit,int flags)128 BH_TABLE *been_here_init(int limit, int flags)
129 {
130     BH_TABLE *dup_filter;
131 
132     dup_filter = (BH_TABLE *) mymalloc(sizeof(*dup_filter));
133     dup_filter->limit = limit;
134     dup_filter->flags = flags;
135     dup_filter->table = htable_create(0);
136     return (dup_filter);
137 }
138 
139 /* been_here_free - destroy duplicate filter */
140 
been_here_free(BH_TABLE * dup_filter)141 void    been_here_free(BH_TABLE *dup_filter)
142 {
143     htable_free(dup_filter->table, (void (*) (void *)) 0);
144     myfree((void *) dup_filter);
145 }
146 
147 /* been_here - duplicate detector with finer control */
148 
been_here(BH_TABLE * dup_filter,const char * fmt,...)149 int     been_here(BH_TABLE *dup_filter, const char *fmt,...)
150 {
151     VSTRING *buf = vstring_alloc(100);
152     int     status;
153     va_list ap;
154 
155     /*
156      * Construct the string to be checked.
157      */
158     va_start(ap, fmt);
159     vstring_vsprintf(buf, fmt, ap);
160     va_end(ap);
161 
162     /*
163      * Do the duplicate check.
164      */
165     status = been_here_fixed(dup_filter, vstring_str(buf));
166 
167     /*
168      * Cleanup.
169      */
170     vstring_free(buf);
171     return (status);
172 }
173 
174 /* been_here_fixed - duplicate detector */
175 
been_here_fixed(BH_TABLE * dup_filter,const char * string)176 int     been_here_fixed(BH_TABLE *dup_filter, const char *string)
177 {
178     VSTRING *folded_string;
179     const char *lookup_key;
180     int     status;
181 
182     /*
183      * Special processing: case insensitive lookup.
184      */
185     if (dup_filter->flags & BH_FLAG_FOLD) {
186 	folded_string = vstring_alloc(100);
187 	lookup_key = casefold(folded_string, string);
188     } else {
189 	folded_string = 0;
190 	lookup_key = string;
191     }
192 
193     /*
194      * Do the duplicate check.
195      */
196     if (htable_locate(dup_filter->table, lookup_key) != 0) {
197 	status = 1;
198     } else {
199 	if (dup_filter->limit <= 0
200 	    || dup_filter->limit > dup_filter->table->used)
201 	    htable_enter(dup_filter->table, lookup_key, (void *) 0);
202 	status = 0;
203     }
204     if (msg_verbose)
205 	msg_info("been_here: %s: %d", string, status);
206 
207     /*
208      * Cleanup.
209      */
210     if (folded_string)
211 	vstring_free(folded_string);
212 
213     return (status);
214 }
215 
216 /* been_here_check - query duplicate detector with finer control */
217 
been_here_check(BH_TABLE * dup_filter,const char * fmt,...)218 int     been_here_check(BH_TABLE *dup_filter, const char *fmt,...)
219 {
220     VSTRING *buf = vstring_alloc(100);
221     int     status;
222     va_list ap;
223 
224     /*
225      * Construct the string to be checked.
226      */
227     va_start(ap, fmt);
228     vstring_vsprintf(buf, fmt, ap);
229     va_end(ap);
230 
231     /*
232      * Do the duplicate check.
233      */
234     status = been_here_check_fixed(dup_filter, vstring_str(buf));
235 
236     /*
237      * Cleanup.
238      */
239     vstring_free(buf);
240     return (status);
241 }
242 
243 /* been_here_check_fixed - query duplicate detector */
244 
been_here_check_fixed(BH_TABLE * dup_filter,const char * string)245 int     been_here_check_fixed(BH_TABLE *dup_filter, const char *string)
246 {
247     VSTRING *folded_string;
248     const char *lookup_key;
249     int     status;
250 
251     /*
252      * Special processing: case insensitive lookup.
253      */
254     if (dup_filter->flags & BH_FLAG_FOLD) {
255 	folded_string = vstring_alloc(100);
256 	lookup_key = casefold(folded_string, string);
257     } else {
258 	folded_string = 0;
259 	lookup_key = string;
260     }
261 
262     /*
263      * Do the duplicate check.
264      */
265     status = (htable_locate(dup_filter->table, lookup_key) != 0);
266     if (msg_verbose)
267 	msg_info("been_here_check: %s: %d", string, status);
268 
269     /*
270      * Cleanup.
271      */
272     if (folded_string)
273 	vstring_free(folded_string);
274 
275     return (status);
276 }
277 
278 /* been_here_drop - remove filter entry with finer control */
279 
been_here_drop(BH_TABLE * dup_filter,const char * fmt,...)280 int     been_here_drop(BH_TABLE *dup_filter, const char *fmt,...)
281 {
282     VSTRING *buf = vstring_alloc(100);
283     int     status;
284     va_list ap;
285 
286     /*
287      * Construct the string to be dropped.
288      */
289     va_start(ap, fmt);
290     vstring_vsprintf(buf, fmt, ap);
291     va_end(ap);
292 
293     /*
294      * Drop the filter entry.
295      */
296     status = been_here_drop_fixed(dup_filter, vstring_str(buf));
297 
298     /*
299      * Cleanup.
300      */
301     vstring_free(buf);
302     return (status);
303 }
304 
305 /* been_here_drop_fixed - remove filter entry */
306 
been_here_drop_fixed(BH_TABLE * dup_filter,const char * string)307 int     been_here_drop_fixed(BH_TABLE *dup_filter, const char *string)
308 {
309     VSTRING *folded_string;
310     const char *lookup_key;
311     int     status;
312 
313     /*
314      * Special processing: case insensitive lookup.
315      */
316     if (dup_filter->flags & BH_FLAG_FOLD) {
317 	folded_string = vstring_alloc(100);
318 	lookup_key = casefold(folded_string, string);
319     } else {
320 	folded_string = 0;
321 	lookup_key = string;
322     }
323 
324     /*
325      * Drop the filter entry.
326      */
327     if ((status = been_here_check_fixed(dup_filter, lookup_key)) != 0)
328 	htable_delete(dup_filter->table, lookup_key, (void (*) (void *)) 0);
329 
330     /*
331      * Cleanup.
332      */
333     if (folded_string)
334 	vstring_free(folded_string);
335 
336     return (status);
337 }
338