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