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