diff options
Diffstat (limited to 'src/util/dict_random.c')
-rw-r--r-- | src/util/dict_random.c | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/src/util/dict_random.c b/src/util/dict_random.c new file mode 100644 index 0000000..36f79b3 --- /dev/null +++ b/src/util/dict_random.c @@ -0,0 +1,179 @@ +/*++ +/* NAME +/* dict_random 3 +/* SUMMARY +/* dictionary manager interface for randomized tables +/* SYNOPSIS +/* #include <dict_random.h> +/* +/* DICT *dict_random_open(name, open_flags, dict_flags) +/* const char *name; +/* int open_flags; +/* int dict_flags; +/* DESCRIPTION +/* dict_random_open() opens an in-memory, read-only, table. +/* Example: "\fBrandmap:{\fIresult_1, ... ,result_n}\fR". +/* +/* Each table query returns a random choice from the specified +/* results. Other table access methods are not supported. +/* +/* The first and last characters of the "randmap:" table name +/* must be '{' and '}'. Within these, individual maps are +/* separated with comma or whitespace. +/* SEE ALSO +/* dict(3) generic dictionary manager +/* 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 <string.h> + +/* Utility library. */ + +#include <msg.h> +#include <mymalloc.h> +#include <myrand.h> +#include <stringops.h> +#include <dict_random.h> + +/* Application-specific. */ + +typedef struct { + DICT dict; /* generic members */ + ARGV *replies; /* reply values */ +} DICT_RANDOM; + +#define STR(x) vstring_str(x) + +/* dict_random_lookup - find randomized-table entry */ + +static const char *dict_random_lookup(DICT *dict, const char *unused_query) +{ + DICT_RANDOM *dict_random = (DICT_RANDOM *) dict; + + DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, + dict_random->replies->argv[myrand() % dict_random->replies->argc]); +} + +/* dict_random_close - disassociate from randomized table */ + +static void dict_random_close(DICT *dict) +{ + DICT_RANDOM *dict_random = (DICT_RANDOM *) dict; + + if (dict_random->replies) + argv_free(dict_random->replies); + dict_free(dict); +} + +static char *dict_random_parse_name(DICT *dict, ARGV **argv, + const char *string, + const char *delim, + const char *parens) +{ + ARGV *argvp = argv_alloc(1); + char *saved_string = mystrdup(string); + char *bp = saved_string; + char *arg; + VSTRING *b64 = 0; + char *err = 0; + + while ((arg = mystrtokq(&bp, delim, parens)) != 0) { + if (dict->flags & DICT_FLAG_SRC_RHS_IS_FILE) { + if ((b64 = dict_file_to_b64(dict, arg)) != 0) { + argv_add(argvp, vstring_str(b64), (char *) 0); + } else { + err = dict_file_get_error(dict); + break; + } + } else { + argv_add(argvp, arg, (char *) 0); + } + } + argv_terminate(argvp); + myfree(saved_string); + *argv = argvp; + return (err); +} + +/* dict_random_open - open a randomized table */ + +DICT *dict_random_open(const char *name, int open_flags, int dict_flags) +{ + DICT_RANDOM *dict_random; + char *saved_name = 0; + size_t len; + char *err = 0; + + /* + * Clarity first. Let the optimizer worry about redundant code. + */ +#define DICT_RANDOM_RETURN(x) do { \ + DICT *__d = (x); \ + if (saved_name != 0) \ + myfree(saved_name); \ + if (err != 0) \ + myfree(err); \ + return (__d); \ + } while (0) + + /* + * Sanity checks. + */ + if (open_flags != O_RDONLY) + DICT_RANDOM_RETURN(dict_surrogate(DICT_TYPE_RANDOM, name, + open_flags, dict_flags, + "%s:%s map requires O_RDONLY access mode", + DICT_TYPE_RANDOM, name)); + + /* + * Bundle up preliminary results. + */ + dict_random = + (DICT_RANDOM *) dict_alloc(DICT_TYPE_RANDOM, name, sizeof(*dict_random)); + dict_random->dict.lookup = dict_random_lookup; + dict_random->dict.close = dict_random_close; + dict_random->dict.flags = dict_flags | DICT_FLAG_PATTERN; + dict_random->replies = 0; + dict_random->dict.owner.status = DICT_OWNER_TRUSTED; + dict_random->dict.owner.uid = 0; + + /* + * Split the table name into its constituent parts. + */ + if ((len = balpar(name, CHARS_BRACE)) == 0 || name[len] != 0 + || *(saved_name = mystrndup(name + 1, len - 2)) == 0 + || (err = dict_random_parse_name(&dict_random->dict, + &dict_random->replies, saved_name, + CHARS_COMMA_SP, CHARS_BRACE)) != 0 + || dict_random->replies->argc == 0) { + dict_random_close(&dict_random->dict); + DICT_RANDOM_RETURN(err == 0 ? + dict_surrogate(DICT_TYPE_RANDOM, name, + open_flags, dict_flags, + "bad syntax: \"%s:%s\"; " + "need \"%s:{value...}\"", + DICT_TYPE_RANDOM, name, + DICT_TYPE_RANDOM) : + dict_surrogate(DICT_TYPE_RANDOM, name, + open_flags, dict_flags, + "%s", err)); + } + dict_file_purge_buffers(&dict_random->dict); + DICT_RANDOM_RETURN(DICT_DEBUG (&dict_random->dict)); +} |