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 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 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 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 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 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 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 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 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