1 /* $NetBSD: been_here.c,v 1.3 2020/03/18 19:05:16 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 /* void been_here_free(dup_filter) 32 /* BH_TABLE *dup_filter; 33 /* DESCRIPTION 34 /* This module implements a simple filter to detect repeated 35 /* occurrences of character strings. 36 /* 37 /* been_here_init() creates an empty duplicate filter. 38 /* 39 /* been_here_fixed() looks up a fixed string in the given table, and 40 /* makes an entry in the table if the string was not found. The result 41 /* is non-zero (true) if the string was found, zero (false) otherwise. 42 /* 43 /* been_here() formats its arguments, looks up the result in the 44 /* given table, and makes an entry in the table if the string was 45 /* not found. The result is non-zero (true) if the formatted result was 46 /* found, zero (false) otherwise. 47 /* 48 /* been_here_check_fixed() and been_here_check() are similar 49 /* but do not update the duplicate filter. 50 /* 51 /* been_here_free() releases storage for a duplicate filter. 52 /* 53 /* Arguments: 54 /* .IP size 55 /* Upper bound on the table size; at most \fIsize\fR strings will 56 /* be remembered. Specify BH_BOUND_NONE to disable the upper bound. 57 /* .IP flags 58 /* Requests for special processing. Specify the bitwise OR of zero 59 /* or more flags: 60 /* .RS 61 /* .IP BH_FLAG_FOLD 62 /* Enable case-insensitive lookup. 63 /* .IP BH_FLAG_NONE 64 /* A manifest constant that requests no special processing. 65 /* .RE 66 /* .IP dup_filter 67 /* The table with remembered names 68 /* .IP string 69 /* Fixed search string. 70 /* .IP format 71 /* Format for building the search string. 72 /* LICENSE 73 /* .ad 74 /* .fi 75 /* The Secure Mailer license must be distributed with this software. 76 /* AUTHOR(S) 77 /* Wietse Venema 78 /* IBM T.J. Watson Research 79 /* P.O. Box 704 80 /* Yorktown Heights, NY 10598, USA 81 /*--*/ 82 83 /* System library. */ 84 85 #include "sys_defs.h" 86 #include <stdlib.h> /* 44BSD stdarg.h uses abort() */ 87 #include <stdarg.h> 88 89 /* Utility library. */ 90 91 #include <msg.h> 92 #include <mymalloc.h> 93 #include <htable.h> 94 #include <vstring.h> 95 #include <stringops.h> 96 97 /* Global library. */ 98 99 #include "been_here.h" 100 101 #define STR(x) vstring_str(x) 102 103 /* been_here_init - initialize duplicate filter */ 104 105 BH_TABLE *been_here_init(int limit, int flags) 106 { 107 BH_TABLE *dup_filter; 108 109 dup_filter = (BH_TABLE *) mymalloc(sizeof(*dup_filter)); 110 dup_filter->limit = limit; 111 dup_filter->flags = flags; 112 dup_filter->table = htable_create(0); 113 return (dup_filter); 114 } 115 116 /* been_here_free - destroy duplicate filter */ 117 118 void been_here_free(BH_TABLE *dup_filter) 119 { 120 htable_free(dup_filter->table, (void (*) (void *)) 0); 121 myfree((void *) dup_filter); 122 } 123 124 /* been_here - duplicate detector with finer control */ 125 126 int been_here(BH_TABLE *dup_filter, const char *fmt,...) 127 { 128 VSTRING *buf = vstring_alloc(100); 129 int status; 130 va_list ap; 131 132 /* 133 * Construct the string to be checked. 134 */ 135 va_start(ap, fmt); 136 vstring_vsprintf(buf, fmt, ap); 137 va_end(ap); 138 139 /* 140 * Do the duplicate check. 141 */ 142 status = been_here_fixed(dup_filter, vstring_str(buf)); 143 144 /* 145 * Cleanup. 146 */ 147 vstring_free(buf); 148 return (status); 149 } 150 151 /* been_here_fixed - duplicate detector */ 152 153 int been_here_fixed(BH_TABLE *dup_filter, const char *string) 154 { 155 VSTRING *folded_string; 156 const char *lookup_key; 157 int status; 158 159 /* 160 * Special processing: case insensitive lookup. 161 */ 162 if (dup_filter->flags & BH_FLAG_FOLD) { 163 folded_string = vstring_alloc(100); 164 lookup_key = casefold(folded_string, string); 165 } else { 166 folded_string = 0; 167 lookup_key = string; 168 } 169 170 /* 171 * Do the duplicate check. 172 */ 173 if (htable_locate(dup_filter->table, lookup_key) != 0) { 174 status = 1; 175 } else { 176 if (dup_filter->limit <= 0 177 || dup_filter->limit > dup_filter->table->used) 178 htable_enter(dup_filter->table, lookup_key, (void *) 0); 179 status = 0; 180 } 181 if (msg_verbose) 182 msg_info("been_here: %s: %d", string, status); 183 184 /* 185 * Cleanup. 186 */ 187 if (folded_string) 188 vstring_free(folded_string); 189 190 return (status); 191 } 192 193 /* been_here_check - query duplicate detector with finer control */ 194 195 int been_here_check(BH_TABLE *dup_filter, const char *fmt,...) 196 { 197 VSTRING *buf = vstring_alloc(100); 198 int status; 199 va_list ap; 200 201 /* 202 * Construct the string to be checked. 203 */ 204 va_start(ap, fmt); 205 vstring_vsprintf(buf, fmt, ap); 206 va_end(ap); 207 208 /* 209 * Do the duplicate check. 210 */ 211 status = been_here_check_fixed(dup_filter, vstring_str(buf)); 212 213 /* 214 * Cleanup. 215 */ 216 vstring_free(buf); 217 return (status); 218 } 219 220 /* been_here_check_fixed - query duplicate detector */ 221 222 int been_here_check_fixed(BH_TABLE *dup_filter, const char *string) 223 { 224 VSTRING *folded_string; 225 const char *lookup_key; 226 int status; 227 228 /* 229 * Special processing: case insensitive lookup. 230 */ 231 if (dup_filter->flags & BH_FLAG_FOLD) { 232 folded_string = vstring_alloc(100); 233 lookup_key = casefold(folded_string, string); 234 } else { 235 folded_string = 0; 236 lookup_key = string; 237 } 238 239 /* 240 * Do the duplicate check. 241 */ 242 status = (htable_locate(dup_filter->table, lookup_key) != 0); 243 if (msg_verbose) 244 msg_info("been_here_check: %s: %d", string, status); 245 246 /* 247 * Cleanup. 248 */ 249 if (folded_string) 250 vstring_free(folded_string); 251 252 return (status); 253 } 254