NetBSD/gnu/dist/postfix/global/maps.c

246 lines
6.4 KiB
C

/*++
/* NAME
/* maps 3
/* SUMMARY
/* multi-dictionary search
/* SYNOPSIS
/* #include <maps.h>
/*
/* MAPS *maps_create(title, map_names, flags)
/* const char *title;
/* const char *map_names;
/* int flags;
/*
/* MAPS *maps_append(maps, map_name, dict_handle)
/* MAPS *maps;
/* const char *map_name;
/* DICT *dict_handle;
/*
/* const char *maps_find(maps, key, flags)
/* MAPS *maps;
/* const char *key;
/* int flags;
/*
/* void maps_free(maps)
/* MAPS *maps;
/* DESCRIPTION
/* This module implements multi-dictionary searches. it goes
/* through the high-level dictionary interface and does file
/* locking. Dictionaries are opened read-only, and in-memory
/* dictionary instances are shared.
/*
/* maps_create() takes list of type:name pairs and opens the
/* named dictionaries.
/* The result is a handle that must be specified along with all
/* other maps_xxx() operations.
/* See dict_open(3) for a description of flags.
/*
/* maps_append() appends a dictionary to an existing handle
/* under the given name. If dict_handle is a null pointer,
/* the named dictionary is opened on the fly.
/*
/* maps_find() searches the specified list of dictionaries
/* in the specified order for the named key. The result is in
/* memory that is overwritten upon each call.
/* The flags argument is either 0 or specifies a filter:
/* for example, DICT_FLAG_FIXED | DICT_FLAG_PATTERN selects
/* dictionaries that have fixed keys or pattern keys.
/*
/* maps_free() releases storage claimed by maps_create()
/* and conveniently returns a null pointer.
/*
/* Arguments:
/* .IP title
/* String used for diagnostics. Typically one specifies the
/* type of information stored in the lookup tables.
/* .IP map_names
/* Null-terminated string with type:name dictionary specifications,
/* separated by whitespace or commas.
/* .IP maps
/* A result from maps_create().
/* .IP key
/* Null-terminated string with a lookup key. Table lookup is case
/* sensitive.
/* DIAGNOSTICS
/* Panic: inappropriate use; fatal errors: out of memory, unable
/* to open database.
/*
/* maps_find() returns a null pointer when the requested
/* information was not found. The global \fIdict_errno\fR
/* variable indicates if the last lookup failed due to a problem.
/* BUGS
/* The dictionary name space is flat, so dictionary names allocated
/* by maps_create() may collide with dictionary names allocated by
/* other methods.
/*
/* This functionality could be implemented by allowing the user to
/* specify dictionary search paths to dict_lookup() or dict_eval().
/* However, that would either require that the dict(3) module adopts
/* someone else's list notation syntax, or that the dict(3) module
/* imposes syntax restrictions onto other software, neither of which
/* is desirable.
/* 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
/*--*/
/* System library. */
#include <sys_defs.h>
#include <string.h>
/* Utility library. */
#include <argv.h>
#include <mymalloc.h>
#include <msg.h>
#include <dict.h>
#include <stringops.h>
#include <split_at.h>
/* Global library. */
#include "mail_conf.h"
#include "maps.h"
/* maps_create - initialize */
MAPS *maps_create(const char *title, const char *map_names, int flags)
{
char *temp;
char *bufp;
static char sep[] = " \t,\r\n";
MAPS *maps;
char *map_type_name;
/*
* Initialize.
*/
maps = (MAPS *) mymalloc(sizeof(*maps));
maps->title = mystrdup(title);
maps->argv = argv_alloc(2);
maps->flags = flags;
/*
* For each specified type:name pair, either register a new dictionary,
* or increment the reference count of an existing one.
*/
if (*map_names) {
bufp = temp = mystrdup(map_names);
while ((map_type_name = mystrtok(&bufp, sep)) != 0)
maps_append(maps, map_type_name, dict_handle(map_type_name));
myfree(temp);
}
return (maps);
}
/* maps_append - append dictionary */
MAPS *maps_append(MAPS *maps, const char *map_type_name, DICT *dict)
{
char *myname = "maps_append";
if (msg_verbose)
msg_info("%s: %s", myname, map_type_name);
if (dict == 0)
dict = dict_open(map_type_name, O_RDONLY, maps->flags);
if ((dict->flags & maps->flags) != maps->flags)
msg_warn("%s: map %s has flags 0%o, want flags 0%o",
myname, map_type_name, dict->flags, maps->flags);
dict_register(map_type_name, dict);
argv_add(maps->argv, map_type_name, ARGV_END);
argv_terminate(maps->argv);
return (maps);
}
/* maps_find - search a list of dictionaries */
const char *maps_find(MAPS *maps, const char *name, int flags)
{
char *myname = "maps_find";
char **map_name;
const char *expansion;
DICT *dict;
/*
* Temp. workaround, for buggy callers that pass zero-length keys when
* given partial addresses.
*/
if (*name == 0)
return (0);
for (map_name = maps->argv->argv; *map_name; map_name++) {
if ((dict = dict_handle(*map_name)) == 0)
msg_panic("%s: dictionary not found: %s", myname, *map_name);
if (flags != 0 && (dict->flags & flags) == 0)
continue;
if ((expansion = dict_get(dict, name)) != 0) {
if (msg_verbose)
msg_info("%s: %s: %s = %s", myname, *map_name, name, expansion);
return (expansion);
} else if (dict_errno != 0) {
break;
}
}
if (msg_verbose)
msg_info("%s: %s: %s", myname, name, dict_errno ?
"search aborted" : "not found");
return (0);
}
/* maps_free - release storage */
MAPS *maps_free(MAPS *maps)
{
char **map_name;
for (map_name = maps->argv->argv; *map_name; map_name++) {
if (msg_verbose)
msg_info("maps_free: %s", *map_name);
dict_unregister(*map_name);
}
myfree(maps->title);
argv_free(maps->argv);
myfree((char *) maps);
return (0);
}
#ifdef TEST
#include <vstring.h>
#include <vstream.h>
#include <vstring_vstream.h>
main(int argc, char **argv)
{
VSTRING *buf = vstring_alloc(100);
MAPS *maps;
const char *result;
if (argc != 2)
msg_fatal("usage: %s maps", argv[0]);
msg_verbose = 2;
maps = maps_create("whatever", argv[1], DICT_FLAG_LOCK);
while (vstring_fgets_nonl(buf, VSTREAM_IN)) {
if ((result = maps_find(maps, vstring_str(buf), 0)) != 0) {
vstream_printf("%s\n", result);
} else if (dict_errno != 0) {
msg_fatal("lookup error: %m");
} else {
vstream_printf("not found\n");
}
vstream_fflush(VSTREAM_OUT);
}
maps_free(maps);
vstring_free(buf);
}
#endif