/* $NetBSD: been_here.c,v 1.4 2022/10/08 16:12:45 christos Exp $ */
/*++
/* NAME
/* been_here 3
/* SUMMARY
/* detect repeated occurrence of string
/* SYNOPSIS
/* #include <been_here.h>
/*
/* BH_TABLE *been_here_init(size, flags)
/* int size;
/* int flags;
/*
/* int been_here_fixed(dup_filter, string)
/* BH_TABLE *dup_filter;
/* char *string;
/*
/* int been_here(dup_filter, format, ...)
/* BH_TABLE *dup_filter;
/* char *format;
/*
/* int been_here_check_fixed(dup_filter, string)
/* BH_TABLE *dup_filter;
/* char *string;
/*
/* int been_here_check(dup_filter, format, ...)
/* BH_TABLE *dup_filter;
/* char *format;
/*
/* int been_here_drop_fixed(dup_filter, string)
/* BH_TABLE *dup_filter;
/* char *string;
/*
/* int been_here_drop(dup_filter, format, ...)
/* BH_TABLE *dup_filter;
/* char *format;
/*
/* void been_here_free(dup_filter)
/* BH_TABLE *dup_filter;
/* DESCRIPTION
/* This module implements a simple filter to detect repeated
/* occurrences of character strings.
/*
/* been_here_init() creates an empty duplicate filter.
/*
/* been_here_fixed() looks up a fixed string in the given table, and
/* makes an entry in the table if the string was not found. The result
/* is non-zero (true) if the string was found, zero (false) otherwise.
/*
/* been_here() formats its arguments, looks up the result in the
/* given table, and makes an entry in the table if the string was
/* not found. The result is non-zero (true) if the formatted result was
/* found, zero (false) otherwise.
/*
/* been_here_check_fixed() and been_here_check() are similar
/* but do not update the duplicate filter.
/*
/* been_here_drop_fixed() looks up a fixed string in the given
/* table, and deletes the entry if the string was found. The
/* result is non-zero (true) if the string was found, zero
/* (false) otherwise.
/*
/* been_here_drop() formats its arguments, looks up the result
/* in the given table, and removes the entry if the formatted
/* result was found. The result is non-zero (true) if the
/* formatted result was found, zero (false) otherwise.
/*
/* been_here_free() releases storage for a duplicate filter.
/*
/* Arguments:
/* .IP size
/* Upper bound on the table size; at most \fIsize\fR strings will
/* be remembered. Specify BH_BOUND_NONE to disable the upper bound.
/* .IP flags
/* Requests for special processing. Specify the bitwise OR of zero
/* or more flags:
/* .RS
/* .IP BH_FLAG_FOLD
/* Enable case-insensitive lookup.
/* .IP BH_FLAG_NONE
/* A manifest constant that requests no special processing.
/* .RE
/* .IP dup_filter
/* The table with remembered names
/* .IP string
/* Fixed search string.
/* .IP format
/* Format for building the search string.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*
/* Wietse Venema
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
/*--*/
/* System library. */
#include "sys_defs.h"
#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
#include <stdarg.h>
/* Utility library. */
#include <msg.h>
#include <mymalloc.h>
#include <htable.h>
#include <vstring.h>
#include <stringops.h>
/* Global library. */
#include "been_here.h"
#define STR(x) vstring_str(x)
/* been_here_init - initialize duplicate filter */
BH_TABLE *been_here_init(int limit, int flags)
{
BH_TABLE *dup_filter;
dup_filter = (BH_TABLE *) mymalloc(sizeof(*dup_filter));
dup_filter->limit = limit;
dup_filter->flags = flags;
dup_filter->table = htable_create(0);
return (dup_filter);
}
/* been_here_free - destroy duplicate filter */
void been_here_free(BH_TABLE *dup_filter)
{
htable_free(dup_filter->table, (void (*) (void *)) 0);
myfree((void *) dup_filter);
}
/* been_here - duplicate detector with finer control */
int been_here(BH_TABLE *dup_filter, const char *fmt,...)
{
VSTRING *buf = vstring_alloc(100);
int status;
va_list ap;
/*
* Construct the string to be checked.
*/
va_start(ap, fmt);
vstring_vsprintf(buf, fmt, ap);
va_end(ap);
/*
* Do the duplicate check.
*/
status = been_here_fixed(dup_filter, vstring_str(buf));
/*
* Cleanup.
*/
vstring_free(buf);
return (status);
}
/* been_here_fixed - duplicate detector */
int been_here_fixed(BH_TABLE *dup_filter, const char *string)
{
VSTRING *folded_string;
const char *lookup_key;
int status;
/*
* Special processing: case insensitive lookup.
*/
if (dup_filter->flags & BH_FLAG_FOLD) {
folded_string = vstring_alloc(100);
lookup_key = casefold(folded_string, string);
} else {
folded_string = 0;
lookup_key = string;
}
/*
* Do the duplicate check.
*/
if (htable_locate(dup_filter->table, lookup_key) != 0) {
status = 1;
} else {
if (dup_filter->limit <= 0
|| dup_filter->limit > dup_filter->table->used)
htable_enter(dup_filter->table, lookup_key, (void *) 0);
status = 0;
}
if (msg_verbose)
msg_info("been_here: %s: %d", string, status);
/*
* Cleanup.
*/
if (folded_string)
vstring_free(folded_string);
return (status);
}
/* been_here_check - query duplicate detector with finer control */
int been_here_check(BH_TABLE *dup_filter, const char *fmt,...)
{
VSTRING *buf = vstring_alloc(100);
int status;
va_list ap;
/*
* Construct the string to be checked.
*/
va_start(ap, fmt);
vstring_vsprintf(buf, fmt, ap);
va_end(ap);
/*
* Do the duplicate check.
*/
status = been_here_check_fixed(dup_filter, vstring_str(buf));
/*
* Cleanup.
*/
vstring_free(buf);
return (status);
}
/* been_here_check_fixed - query duplicate detector */
int been_here_check_fixed(BH_TABLE *dup_filter, const char *string)
{
VSTRING *folded_string;
const char *lookup_key;
int status;
/*
* Special processing: case insensitive lookup.
*/
if (dup_filter->flags & BH_FLAG_FOLD) {
folded_string = vstring_alloc(100);
lookup_key = casefold(folded_string, string);
} else {
folded_string = 0;
lookup_key = string;
}
/*
* Do the duplicate check.
*/
status = (htable_locate(dup_filter->table, lookup_key) != 0);
if (msg_verbose)
msg_info("been_here_check: %s: %d", string, status);
/*
* Cleanup.
*/
if (folded_string)
vstring_free(folded_string);
return (status);
}
/* been_here_drop - remove filter entry with finer control */
int been_here_drop(BH_TABLE *dup_filter, const char *fmt,...)
{
VSTRING *buf = vstring_alloc(100);
int status;
va_list ap;
/*
* Construct the string to be dropped.
*/
va_start(ap, fmt);
vstring_vsprintf(buf, fmt, ap);
va_end(ap);
/*
* Drop the filter entry.
*/
status = been_here_drop_fixed(dup_filter, vstring_str(buf));
/*
* Cleanup.
*/
vstring_free(buf);
return (status);
}
/* been_here_drop_fixed - remove filter entry */
int been_here_drop_fixed(BH_TABLE *dup_filter, const char *string)
{
VSTRING *folded_string;
const char *lookup_key;
int status;
/*
* Special processing: case insensitive lookup.
*/
if (dup_filter->flags & BH_FLAG_FOLD) {
folded_string = vstring_alloc(100);
lookup_key = casefold(folded_string, string);
} else {
folded_string = 0;
lookup_key = string;
}
/*
* Drop the filter entry.
*/
if ((status = been_here_check_fixed(dup_filter, lookup_key)) != 0)
htable_delete(dup_filter->table, lookup_key, (void (*) (void *)) 0);
/*
* Cleanup.
*/
if (folded_string)
vstring_free(folded_string);
return (status);
}