-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
Workaround: Solaris NIS alias maps need special entries
(YP_MASTER_NAME, YP_LAST_MODIFIED). What's worse, normal
keys/values include a null byte at the end, but the YP_XXX
- ones don't. File: postalias/postalias.c.
+ ones don't. Problem reported by Walcir Fontanini, state
+ university of Campinas, Brazil. File: postalias/postalias.c.
Compatibility: Solaris NIS apparently does include a null
byte at the end of keys and values. File: util/sys_defs.h.
Bugfix: pcre didn't handle \\ right. Lamont Jones, Hewlett-
Packard. File: util/dict_pcre.c.
+19990326
+
+ Compatibility: Postfix now puts to spaces after the sender
+ in a "From sender date..." header. Found by John A. Martin,
+ fixed by Lamont Jones, Hewlett-Packard.
+
+ Bugfix: when a recipient appeared multiple times in a local
+ alias or include expansion, the delivery status could be
+ left uninitialized, causing the mail to be deferred and
+ delivered again. File: local/recipient.c.
+
+19990327
+
+ Cleanup: the dictionary routines now take an extra flag
+ argument to control such things as warning about duplicates,
+ and appending null bytes to key/value. This was needed for
+ a clean implementation of NIS master alias maps support.
+
+ Feature: POSIX regular expressions by Lamont Jones.
+
Future:
Planned: must be able to list the same hash table in
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
--- /dev/null
+# Sample regexp lookup "table".
+#
+# Format is /regexp/flags or /regexp/flags!/regexp/flags
+# where regexp is a regular expression as found in regexp(5), and flags are
+# i: toggle ignore case (REG_ICASE - default is to ignore case)
+# x: toggle extended expression (REG_EXTENDED - default is extended)
+# m: toggle multiline mode (REG_NEWLINE - default is non-multiline mode)
+#
+# In order for a line to match, the first regexp must match, and the
+# second (if present) must not match. The first matching line wins,
+# terminating processing of the ruleset.
+
+# Postmaster is OK, that way they can talk to us about how to fix their problem.
+/^postmaster@.*$/ OK
+
+# Protect your outgoing majordomo exploders
+/^(.*)-outgoing@(.*)$/!/^owner-.*/ 550 Use ${1}@${2} instead
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
quote_822_local(buf, sender);
if (flags & MAIL_COPY_FROM) {
time(&now);
- vstream_fprintf(dst, "From %s %s", *sender == 0 ?
+ vstream_fprintf(dst, "From %s %s", *sender == 0 ?
MAIL_ADDR_MAIL_DAEMON :
vstring_str(buf),
asctime(localtime(&now)));
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Snapshot-19990325"
+#define DEF_MAIL_VERSION "Snapshot-19990327"
extern char *var_mail_version;
/* LICENSE
if (msg_verbose)
msg_info("%s: %s", myname, map_type_name);
if ((dict = dict_handle(map_type_name)) == 0)
- dict = dict_open(map_type_name, O_RDONLY);
+ dict = dict_open(map_type_name, O_RDONLY, 0);
dict_register(map_type_name, dict);
argv_add(maps->argv, map_type_name, ARGV_END);
}
/* DESCRIPTION
/* .nf
+ /*
+ * Utility library.
+ */
+#include <dict.h>
+
/*
* A database handle is an opaque structure. The user is not supposed to
* know its implementation.
*/
typedef struct MKMAP {
- struct DICT *(*open) (const char *, int);
+ struct DICT *(*open) (const char *, int, int);
struct DICT *dict;
char *lock_file;
int lock_fd;
} MKMAP;
-extern MKMAP *mkmap_open(const char *, const char *, int);
+extern MKMAP *mkmap_open(const char *, const char *, int, int);
extern void mkmap_append(MKMAP *, const char *, const char *);
extern void mkmap_close(MKMAP *);
/* mkmap_db_open - create or open database */
static MKMAP *mkmap_db_open(const char *path,
- DICT *(*db_open) (const char *, int))
+ DICT *(*db_open) (const char *, int, int))
{
MKMAP *mkmap = (MKMAP *) mymalloc(sizeof(*mkmap));
/* SYNOPSIS
/* #include <mkmap.h>
/*
-/* MKMAP *mkmap_open(type, path, flags)
+/* MKMAP *mkmap_open(type, path, open_flags, dict_flags)
/* char *type;
/* char *path;
-/* int flags;
+/* int open_flags;
+/* int dict_flags;
/*
/* void mkmap_append(mkmap, key, value, lineno)
/* MKMAP *mkmap;
/* appending the appropriate suffixes to the specified filename.
/* Before the database is updated, it is locked for exclusive
/* access, and signal delivery is suspended.
+/* See dict(3) for a description of \fBopen_flags\fR and \fBdict_flags\fR.
/* All errors are fatal.
/*
/* mkmap_append() appends the named (key, value) pair to the
/* database. Update errors are fatal; duplicate keys are ignored
/* (but a warning is issued).
+/* \fBlineno\fR is used for diagnostics.
/*
/* mkmap_close() closes the database, releases any locks,
/* and resumes signal delivery. All errors are fatal.
/* mkmap_open - create or truncate database */
-MKMAP *mkmap_open(const char *type, const char *path, int flags)
+MKMAP *mkmap_open(const char *type, const char *path,
+ int open_flags, int dict_flags)
{
MKMAP *mkmap;
MKMAP_OPEN_INFO *mp;
* Truncate the database upon open, and update it. Read-write mode is
* needed because the underlying routines read as well as write.
*/
- mkmap->dict = mkmap->open(path, flags);
+ mkmap->dict = mkmap->open(path, open_flags, dict_flags);
mkmap->dict->fd = -1; /* XXX just in case */
mkmap->dict->flags |= DICT_FLAG_DUP_WARN;
return (mkmap);
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
FW_CONTEXT *fw_context = (FW_CONTEXT *) context;
char *ptr;
+ if (fw_context->failures)
+ return;
+
/*
* Find out what data to substitute.
*/
static int deliver_switch(LOCAL_STATE state, USER_ATTR usr_attr)
{
char *myname = "deliver_switch";
- int status;
+ int status = 0;
/*
* Make verbose logging easier to understand.
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
postalias.o: ../include/config.h
postalias.o: ../include/mail_params.h
postalias.o: ../include/mkmap.h
+postalias.o: ../include/dict.h
/* postalias - create or update alias database */
-static void postalias(char *map_type, char *path_name, int incremental)
+static void postalias(char *map_type, char *path_name,
+ int open_flags, int dict_flags)
{
VSTREAM *source_fp;
VSTRING *line_buffer;
line_buffer = vstring_alloc(100);
key_buffer = vstring_alloc(100);
value_buffer = vstring_alloc(100);
- if (incremental) {
+ if ((open_flags & O_TRUNC) == 0) {
source_fp = VSTREAM_IN;
vstream_control(source_fp, VSTREAM_CTL_PATH, "stdin", VSTREAM_CTL_END);
} else if ((source_fp = vstream_fopen(path_name, O_RDONLY, 0)) == 0) {
* Open the database, create it when it does not exist, truncate it when
* it does exist, and lock out any spectators.
*/
- mkmap = mkmap_open(map_type, path_name, incremental ?
- O_RDWR | O_CREAT : O_RDWR | O_CREAT | O_TRUNC);
+ mkmap = mkmap_open(map_type, path_name, open_flags, dict_flags);
/*
* Add records to the database.
mkmap_append(mkmap, "@", "@");
/*
- * NIS compatibility: add time and master info.
+ * NIS compatibility: add time and master info. Unlike other information,
+ * this information MUST be written without a trailing null appended to
+ * key or value.
*/
+ mkmap->dict->flags &= ~DICT_FLAG_TRY1NULL;
+ mkmap->dict->flags |= DICT_FLAG_TRY0NULL;
vstring_sprintf(value_buffer, "%010ld", (long) time((time_t *) 0));
mkmap_append(mkmap, "YP_LAST_MODIFIED", STR(value_buffer));
mkmap_append(mkmap, "YP_MASTER_NAME", get_hostname());
static NORETURN usage(char *myname)
{
- msg_fatal("usage: %s [-c config_directory] [-i] [-v] [output_type:]file...",
+ msg_fatal("usage: %s [-c config_directory] [-i] [-v] [-w] [output_type:]file...",
myname);
}
int fd;
char *slash;
struct stat st;
- int incremental = 0;
+ int open_flags = O_RDWR | O_CREAT | O_TRUNC;
+ int dict_flags = DICT_FLAG_DUP_WARN;
/*
* Be consistent with file permissions.
/*
* Parse JCL.
*/
- while ((ch = GETOPT(argc, argv, "c:iv")) > 0) {
+ while ((ch = GETOPT(argc, argv, "c:ivw")) > 0) {
switch (ch) {
default:
usage(argv[0]);
msg_fatal("out of memory");
break;
case 'i':
- incremental = 1;
+ open_flags &= ~O_TRUNC;
break;
case 'v':
msg_verbose++;
break;
+ case 'w':
+ dict_flags &= ~DICT_FLAG_DUP_WARN;
+ dict_flags |= DICT_FLAG_DUP_IGNORE;
+ break;
}
}
read_config();
usage(argv[0]);
while (optind < argc) {
if ((path_name = split_at(argv[optind], ':')) != 0) {
- postalias(argv[optind], path_name, incremental);
+ postalias(argv[optind], path_name, open_flags, dict_flags);
} else {
- postalias(var_db_type, argv[optind], incremental);
+ postalias(var_db_type, argv[optind], open_flags, dict_flags);
}
optind++;
}
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
postmap.o: ../include/config.h
postmap.o: ../include/mail_params.h
postmap.o: ../include/mkmap.h
+postmap.o: ../include/dict.h
/* postmap - create or update mapping database */
-static void postmap(char *map_type, char *path_name, int incremental)
+static void postmap(char *map_type, char *path_name,
+ int open_flags, int dict_flags)
{
VSTREAM *source_fp;
VSTRING *line_buffer;
* Initialize.
*/
line_buffer = vstring_alloc(100);
- if (incremental) {
+ if ((open_flags & O_TRUNC) == 0) {
source_fp = VSTREAM_IN;
vstream_control(source_fp, VSTREAM_CTL_PATH, "stdin", VSTREAM_CTL_END);
} else if ((source_fp = vstream_fopen(path_name, O_RDONLY, 0)) == 0) {
}
/*
- * Open the database, create it when it does not exist, truncate it when
- * it does exist, and lock out any spectators.
+ * Open the database, optionally create it when it does not exist,
+ * optionally truncate it when it does exist, and lock out any
+ * spectators.
*/
- mkmap = mkmap_open(map_type, path_name, incremental ?
- O_RDWR | O_CREAT : O_RDWR | O_CREAT | O_TRUNC);
+ mkmap = mkmap_open(map_type, path_name, open_flags, dict_flags);
/*
* Add records to the database.
static NORETURN usage(char *myname)
{
- msg_fatal("usage: %s [-c config_directory] [-i] [-v] [output_type:]file...",
+ msg_fatal("usage: %s [-c config_directory] [-i] [-v] [-w] [output_type:]file...",
myname);
}
int fd;
char *slash;
struct stat st;
- int incremental = 0;
+ int open_flags = O_RDWR | O_CREAT | O_TRUNC;
+ int dict_flags = DICT_FLAG_DUP_WARN;
/*
* Be consistent with file permissions.
/*
* Parse JCL.
*/
- while ((ch = GETOPT(argc, argv, "c:iv")) > 0) {
+ while ((ch = GETOPT(argc, argv, "c:ivw")) > 0) {
switch (ch) {
default:
usage(argv[0]);
msg_fatal("out of memory");
break;
case 'i':
- incremental = 1;
+ open_flags &= ~O_TRUNC;
break;
case 'v':
msg_verbose++;
break;
+ case 'w':
+ dict_flags &= ~DICT_FLAG_DUP_WARN;
+ dict_flags |= DICT_FLAG_DUP_IGNORE;
+ break;
}
}
read_config();
usage(argv[0]);
while (optind < argc) {
if ((path_name = split_at(argv[optind], ':')) != 0) {
- postmap(argv[optind], path_name, incremental);
+ postmap(argv[optind], path_name, open_flags, dict_flags);
} else {
- postmap(var_db_type, argv[optind], incremental);
+ postmap(var_db_type, argv[optind], open_flags, dict_flags);
}
optind++;
}
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
while ((name = mystrtok(&bp, " \t\r\n,")) != 0) {
argv_add(argv, name, (char *) 0);
if (strchr(name, ':') && dict_handle(name) == 0)
- dict_register(name, dict_open(name, 0));
+ dict_register(name, dict_open(name, 0, 0));
}
argv_terminate(argv);
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
-TDICT_NODE
-TDICT_OPEN_INFO
-TDICT_PCRE
+-TDICT_REGEXP
+-TDICT_REGEXP_LINE
-TDICT_UNIX
-TDNS_FIXED
-TDNS_REPLY
unsafe.c username.c valid_hostname.c vbuf.c vbuf_print.c \
vstream.c vstream_popen.c vstring.c vstring_vstream.c writable.c \
write_buf.c write_wait.c dict_unix.c dict_pcre.c stream_listen.c \
- stream_connect.c stream_trigger.c
+ stream_connect.c stream_trigger.c dict_regexp.c
OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
close_on_exec.o concatenate.o dict.o dict_db.o dict_dbm.o \
dict_env.o dict_ht.o dict_ldap.o dict_ni.o dict_nis.o \
unsafe.o username.o valid_hostname.o vbuf.o vbuf_print.o \
vstream.o vstream_popen.o vstring.o vstring_vstream.o writable.o \
write_buf.o write_wait.o dict_unix.o dict_pcre.o stream_listen.o \
- stream_connect.o stream_trigger.o
+ stream_connect.o stream_trigger.o dict_regexp.o
HDRS = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \
dict_dbm.h dict_env.h dict_ht.h dict_ldap.h dict_ni.h dict_nis.h \
dict_nisplus.h dir_forest.h events.h exec_command.h find_inet.h \
sigdelay.h split_at.h stat_as.h stringops.h sys_defs.h \
timed_connect.h timed_wait.h trigger.h username.h valid_hostname.h \
vbuf.h vbuf_print.h vstream.h vstring.h vstring_vstream.h \
- dict_unix.h dict_pcre.h
+ dict_unix.h dict_pcre.h dict_regexp.h
TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
stream_test.c
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
dict_open.o: dict_ni.h
dict_open.o: dict_ldap.h
dict_open.o: dict_pcre.h
+dict_open.o: dict_regexp.h
dict_open.o: stringops.h
dict_open.o: split_at.h
dict_pcre.o: dict_pcre.c
dict_pcre.o: sys_defs.h
+dict_regexp.o: dict_regexp.c
+dict_regexp.o: sys_defs.h
+dict_regexp.o: mymalloc.h
+dict_regexp.o: msg.h
+dict_regexp.o: safe.h
+dict_regexp.o: vstream.h
+dict_regexp.o: vbuf.h
+dict_regexp.o: vstring.h
+dict_regexp.o: stringops.h
+dict_regexp.o: readline.h
+dict_regexp.o: dict.h
+dict_regexp.o: dict_regexp.h
+dict_regexp.o: mac_parse.h
dict_unix.o: dict_unix.c
dict_unix.o: sys_defs.h
dict_unix.o: msg.h
percentm.o: percentm.h
posix_signals.o: posix_signals.c
posix_signals.o: sys_defs.h
+posix_signals.o: posix_signals.h
printable.o: printable.c
printable.o: sys_defs.h
printable.o: stringops.h
#define DICT_FLAG_DUP_WARN (1<<0) /* if file, warn about dups */
#define DICT_FLAG_DUP_IGNORE (1<<1) /* if file, ignore dups */
+#define DICT_FLAG_TRY0NULL (1<<2) /* do not append 0 to key/value */
+#define DICT_FLAG_TRY1NULL (1<<3) /* append 0 to key/value */
extern int dict_unknown_allowed;
extern int dict_errno;
* Low-level interface, with physical dictionary handles and no implied
* locking.
*/
-extern DICT *dict_open(const char *, int);
-extern DICT *dict_open3(const char *, const char *, int);
+extern DICT *dict_open(const char *, int, int);
+extern DICT *dict_open3(const char *, const char *, int, int);
#define dict_get(dp, key) (dp)->lookup((dp), (key))
#define dict_put(dp, key, val) (dp)->update((dp), (key), (val))
/* SYNOPSIS
/* #include <dict_db.h>
/*
-/* DICT *dict_hash_open(path, flags)
+/* DICT *dict_hash_open(path, open_flags, dict_flags)
/* const char *path;
-/* int flags;
+/* int open_flags;
+/* int dict_flags;
/*
-/* DICT *dict_btree_open(path, flags)
+/* DICT *dict_btree_open(path, open_flags, dict_flags)
/* const char *path;
-/* int flags;
+/* int open_flags;
+/* int dict_flags;
/* DESCRIPTION
/* dict_XXX_open() opens the specified DB database. The result is
/* a pointer to a structure that can be used to access the dictionary
/* Arguments:
/* .IP path
/* The database pathname, not including the ".db" suffix.
-/* .IP flags
-/* flags passed to dbopen().
+/* .IP open_flags
+/* Flags passed to dbopen().
+/* .IP dict_flags
+/* Flags used by the dictionary interface.
/* SEE ALSO
/* dict(3) generic dictionary manager
/* DIAGNOSTICS
char *path; /* pathname */
} DICT_DB;
-#define DICT_DB_TRY0NULL (1<<0)
-#define DICT_DB_TRY1NULL (1<<1)
-
#define DICT_DB_CACHE_SIZE (1024 * 1024)
#define DICT_DB_NELM 4096
* See if this DB file was written with one null byte appended to key and
* value.
*/
- if (dict_db->flags & DICT_DB_TRY1NULL) {
+ if (dict_db->flags & DICT_FLAG_TRY1NULL) {
db_key.data = (void *) name;
db_key.size = strlen(name) + 1;
if ((status = db->get(db, &db_key, &db_value, 0)) < 0)
msg_fatal("error reading %s: %m", dict_db->path);
if (status == 0) {
- dict_db->flags &= ~DICT_DB_TRY0NULL;
+ dict_db->flags &= ~DICT_FLAG_TRY0NULL;
return (db_value.data);
}
}
* See if this DB file was written with no null byte appended to key and
* value.
*/
- if (dict_db->flags & DICT_DB_TRY0NULL) {
+ if (dict_db->flags & DICT_FLAG_TRY0NULL) {
db_key.data = (void *) name;
db_key.size = strlen(name);
if ((status = db->get(db, &db_key, &db_value, 0)) < 0)
if (buf == 0)
buf = vstring_alloc(10);
vstring_strncpy(buf, db_value.data, db_value.size);
- dict_db->flags &= ~DICT_DB_TRY1NULL;
+ dict_db->flags &= ~DICT_FLAG_TRY1NULL;
return (vstring_str(buf));
}
}
* If undecided about appending a null byte to key and value, choose a
* default depending on the platform.
*/
- if ((dict_db->flags & DICT_DB_TRY1NULL)
- && (dict_db->flags & DICT_DB_TRY0NULL)) {
+ if ((dict_db->flags & DICT_FLAG_TRY1NULL)
+ && (dict_db->flags & DICT_FLAG_TRY0NULL)) {
#ifdef DB_NO_TRAILING_NULL
- dict_db->flags = DICT_DB_TRY0NULL;
+ dict_db->flags = DICT_FLAG_TRY0NULL;
#else
- dict_db->flags = DICT_DB_TRY1NULL;
+ dict_db->flags = DICT_FLAG_TRY1NULL;
#endif
}
/*
* Optionally append a null byte to key and value.
*/
- if (dict_db->flags & DICT_DB_TRY1NULL) {
+ if (dict_db->flags & DICT_FLAG_TRY1NULL) {
db_key.size++;
db_value.size++;
}
/* dict_db_open - open data base */
-static DICT *dict_db_open(const char *path, int flags, int type, void *tweak)
+static DICT *dict_db_open(const char *path, int flags, int type,
+ void *tweak, int dict_flags)
{
DICT_DB *dict_db;
DB *db;
dict_db->dict.close = dict_db_close;
dict_db->dict.fd = db->fd(db);
close_on_exec(dict_db->dict.fd, CLOSE_ON_EXEC);
- dict_db->flags = DICT_DB_TRY1NULL | DICT_DB_TRY0NULL;
+ dict_db->dict.flags = dict_flags;
+ if ((flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
+ dict_db->dict.flags |= (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL);
dict_db->db = db;
dict_db->path = db_path;
return (&dict_db->dict);
/* dict_hash_open - create association with data base */
-DICT *dict_hash_open(const char *path, int flags)
+DICT *dict_hash_open(const char *path, int open_flags, int dict_flags)
{
HASHINFO tweak;
memset((char *) &tweak, 0, sizeof(tweak));
tweak.nelem = DICT_DB_NELM;
tweak.cachesize = DICT_DB_CACHE_SIZE;
- return (dict_db_open(path, flags, DB_HASH, (void *) &tweak));
+ return (dict_db_open(path, open_flags, DB_HASH, (void *) &tweak, dict_flags));
}
/* dict_btree_open - create association with data base */
-DICT *dict_btree_open(const char *path, int flags)
+DICT *dict_btree_open(const char *path, int open_flags, int dict_flags)
{
BTREEINFO tweak;
memset((char *) &tweak, 0, sizeof(tweak));
tweak.cachesize = DICT_DB_CACHE_SIZE;
- return (dict_db_open(path, flags, DB_BTREE, (void *) &tweak));
+ return (dict_db_open(path, open_flags, DB_BTREE, (void *) &tweak, dict_flags));
}
#endif
/*
* External interface.
*/
-extern DICT *dict_hash_open(const char *, int);
-extern DICT *dict_btree_open(const char *, int);
+extern DICT *dict_hash_open(const char *, int, int);
+extern DICT *dict_btree_open(const char *, int, int);
/* LICENSE
/* .ad
/* SYNOPSIS
/* #include <dict_dbm.h>
/*
-/* DICT *dict_dbm_open(path, flags)
+/* DICT *dict_dbm_open(path, open_flags, dict_flags)
/* const char *name;
/* const char *path;
-/* int flags;
+/* int open_flags;
+/* int dict_flags;
/* DESCRIPTION
/* dict_dbm_open() opens the named DBM database and makes it available
/* via the generic interface described in dict_open(3).
char *path; /* pathname */
} DICT_DBM;
-#define DICT_DBM_TRY0NULL (1<<0)
-#define DICT_DBM_TRY1NULL (1<<1)
-
/* dict_dbm_lookup - find database entry */
static const char *dict_dbm_lookup(DICT *dict, const char *name)
* See if this DBM file was written with one null byte appended to key
* and value.
*/
- if (dict_dbm->flags & DICT_DBM_TRY1NULL) {
+ if (dict_dbm->flags & DICT_FLAG_TRY1NULL) {
dbm_key.dptr = (void *) name;
dbm_key.dsize = strlen(name) + 1;
dbm_value = dbm_fetch(dict_dbm->dbm, dbm_key);
if (dbm_value.dptr != 0) {
- dict_dbm->flags &= ~DICT_DBM_TRY0NULL;
+ dict_dbm->flags &= ~DICT_FLAG_TRY0NULL;
return (dbm_value.dptr);
}
}
* See if this DBM file was written with no null byte appended to key and
* value.
*/
- if (dict_dbm->flags & DICT_DBM_TRY0NULL) {
+ if (dict_dbm->flags & DICT_FLAG_TRY0NULL) {
dbm_key.dptr = (void *) name;
dbm_key.dsize = strlen(name);
dbm_value = dbm_fetch(dict_dbm->dbm, dbm_key);
if (buf == 0)
buf = vstring_alloc(10);
vstring_strncpy(buf, dbm_value.dptr, dbm_value.dsize);
- dict_dbm->flags &= ~DICT_DBM_TRY1NULL;
+ dict_dbm->flags &= ~DICT_FLAG_TRY1NULL;
return (vstring_str(buf));
}
}
* If undecided about appending a null byte to key and value, choose a
* default depending on the platform.
*/
- if ((dict_dbm->flags & DICT_DBM_TRY1NULL)
- && (dict_dbm->flags & DICT_DBM_TRY0NULL)) {
+ if ((dict_dbm->flags & DICT_FLAG_TRY1NULL)
+ && (dict_dbm->flags & DICT_FLAG_TRY0NULL)) {
#ifdef DBM_NO_TRAILING_NULL
- dict_dbm->flags = DICT_DBM_TRY0NULL;
+ dict_dbm->flags = DICT_FLAG_TRY0NULL;
#else
- dict_dbm->flags = DICT_DBM_TRY1NULL;
+ dict_dbm->flags = DICT_FLAG_TRY1NULL;
#endif
}
/*
* Optionally append a null byte to key and value.
*/
- if ((dict_dbm->flags & DICT_DBM_TRY1NULL)
- && strcmp(name, "YP_MASTER_NAME") != 0
- && strcmp(name, "YP_LAST_MODIFIED") != 0) {
+ if (dict_dbm->flags & DICT_FLAG_TRY1NULL) {
dbm_key.dsize++;
dbm_value.dsize++;
}
/* dict_dbm_open - open DBM data base */
-DICT *dict_dbm_open(const char *path, int flags)
+DICT *dict_dbm_open(const char *path, int open_flags, int dict_flags)
{
DICT_DBM *dict_dbm;
DBM *dbm;
/*
* XXX SunOS 5.x has no const in dbm_open() prototype.
*/
- if ((dbm = dbm_open((char *) path, flags, 0644)) == 0)
+ if ((dbm = dbm_open((char *) path, open_flags, 0644)) == 0)
msg_fatal("open database %s.{dir,pag}: %m", path);
dict_dbm = (DICT_DBM *) mymalloc(sizeof(*dict_dbm));
dict_dbm->dict.close = dict_dbm_close;
dict_dbm->dict.fd = dbm_dirfno(dbm);
close_on_exec(dict_dbm->dict.fd, CLOSE_ON_EXEC);
- dict_dbm->flags = DICT_DBM_TRY0NULL | DICT_DBM_TRY1NULL;
+ dict_dbm->dict.flags = dict_flags;
+ if (dict_flagsflags & (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL)) == 0)
+ dict_dbm->dict.flags |= (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL);
dict_dbm->dbm = dbm;
dict_dbm->path = mystrdup(path);
/*
* External interface.
*/
-extern DICT *dict_dbm_open(const char *, int);
+extern DICT *dict_dbm_open(const char *, int, int);
/* LICENSE
/* .ad
/* SYNOPSIS
/* #include <dict_env.h>
/*
-/* DICT *dict_env_open(name, flags)
+/* DICT *dict_env_open(name, dummy, dict_flags)
/* const char *name;
-/* int flags;
+/* int dummy;
+/* int dict_flags;
/* DESCRIPTION
/* dict_env_open() opens the environment variable array and
/* makes it accessible via the generic operations documented
-/* in dict_open(3). The \fIname\fR and \fIflags\fR arguments
+/* in dict_open(3). The \fIname\fR and \fIdummy\fR arguments
/* are ignored.
/* SEE ALSO
/* dict(3) generic dictionary manager
/* dict_env_open - make association with environment array */
-DICT *dict_env_open(const char *unused_name, int unused_flags)
+DICT *dict_env_open(const char *unused_name, int unused_flags, int dict_flags)
{
DICT *dict;
dict->lookup = dict_env_lookup;
dict->update = dict_env_update;
dict->close = dict_env_close;
+ dict->flags = dict_flags;
dict->fd = -1;
return (dict);
}
/*
* External interface.
*/
-extern DICT *dict_env_open(const char *, int);
+extern DICT *dict_env_open(const char *, int, int);
/* LICENSE
/* .ad
/* SYNOPSIS
/* #include <dict_ldap.h>
/*
-/* DICT *dict_ldap_open(attribute, dummy)
+/* DICT *dict_ldap_open(attribute, dummy, dict_flags)
/* const char *attribute;
/* int dummy;
+/* int dict_flags;
/* DESCRIPTION
/* dict_ldap_open() makes LDAP user information accessible via
/* the generic dictionary operations described in dict_open(3).
/* dict_ldap_open - create association with data base */
-DICT *dict_ldap_open(const char *ldapsource, int flags)
+DICT *dict_ldap_open(const char *ldapsource, int dummy, int dict_flags)
{
char *myname = "dict_ldap_open";
DICT_LDAP *dict_ldap;
dict_ldap->dict.update = dict_ldap_update;
dict_ldap->dict.close = dict_ldap_close;
dict_ldap->dict.fd = -1;
+ dict_ldap->dict.flags = dict_flags;
if (msg_verbose)
msg_info("%s: using LDAP source %s", myname, ldapsource);
/*
* External interface.
*/
-extern DICT *dict_ldap_open(const char *, int);
+extern DICT *dict_ldap_open(const char *, int, int);
/* AUTHOR(S)
/* Wietse Venema
- /*
- * The NetInfo software is not bundled with IBM's public release. It will be
- * made available as contributed software from http://www.postfix.org/
- */
+/*++
+/* NAME
+/* dict_ni 3
+/* SUMMARY
+/* dictionary manager interface to NetInfo
+/* SYNOPSIS
+/* #include <dict_ni.h>
+/*
+/* DICT *dict_ni_open(path, dummy, dict_flags)
+/* char *path;
+/* int dummy;
+/* int dict_flags;
+/* DESCRIPTION
+/* dict_ni_open() `opens' the named NetInfo database. The result is
+/* a pointer to a structure that can be used to access the dictionary
+/* using the generic methods documented in dict_open(3).
+/* DIAGNOSTICS
+/* dict_ni_register() returns 0 in case of success, -1 in case
+/* of problems.
+/* Fatal errors: NetInfo errors, out of memory.
+/* SEE ALSO
+/* dict(3) generic dictionary manager
+/* netinfo(3N) data base subroutines
+/* AUTHOR(S)
+/* Pieter Schoenmakers
+/* Eindhoven University of Technology
+/* P.O. Box 513
+/* 5600 MB Eindhoven
+/* The Netherlands
+/*--*/
+
#include "sys_defs.h"
#ifdef HAS_NETINFO
-#error "This requires contributed software from http://www.postfix.org/"
+
+/* System library. */
+
+#include <stdio.h>
+#include <netinfo/ni.h>
+
+/* Utility library. */
+
+#include "dict.h"
+#include "dict_ni.h"
+#include "msg.h"
+#include "mymalloc.h"
+
+typedef struct {
+ DICT dict; /* my super */
+ char *path; /* directory path */
+} DICT_NI;
+
+ /*
+ * We'd like other possibilities, but that is not possible in the current
+ * dictionary setup... An example of a different setup: use `members' for
+ * multi-valued lookups (to be compatible with /aliases), and `value' for
+ * single-valued tables.
+ */
+#define NETINFO_PROP_KEY "name"
+#define NETINFO_PROP_VALUE "members"
+#define NETINFO_VALUE_SEP ","
+
+#define NETINFO_MAX_DOMAIN_DEPTH 100
+
+/* Hard worker doing lookups. Returned value is statically allocated and
+ reused each call. */
+static const char *dict_ni_do_lookup(char *path, char *key_prop,
+ const char *key_value, char *val_prop)
+{
+ unsigned int result_cap = 0;
+ static char *result = 0;
+
+ char *return_val = 0;
+ ni_namelist values;
+ int depth = 0;
+ void *domain;
+ void *next_domain;
+ char *query;
+ ni_status r;
+ ni_id dir;
+
+ if (msg_verbose)
+ msg_info("ni_lookup %s %s=%s", path, key_prop, key_value);
+
+ r = ni_open(NULL, ".", &domain);
+ if (r != NI_OK) {
+ msg_warn("ni_open `.': %d", r);
+ return NULL;
+ }
+ query = alloca(strlen(path) + strlen(key_prop) + 3 + strlen(key_value));
+ sprintf(query, "%s/%s=%s", path, key_prop, key_value);
+
+ for (;;) {
+
+ /*
+ * What does it _mean_ if we find the directory but not the value?
+ */
+ if (ni_pathsearch(domain, &dir, query) == NI_OK
+ && ni_lookupprop(domain, &dir, val_prop, &values) == NI_OK)
+ if (values.ni_namelist_len <= 0)
+ ni_namelist_free(&values);
+ else {
+ unsigned int i,
+ l,
+ n;
+
+ for (i = l = 0; i < values.ni_namelist_len; i++)
+ l += 1 + strlen(values.ni_namelist_val[i]);
+ if (result_cap < l) {
+ if (result)
+ myfree(result);
+ result_cap = l + 100;
+ result = mymalloc(result_cap);
+ }
+ for (i = l = 0; i < values.ni_namelist_len; i++) {
+ n = strlen(values.ni_namelist_val[i]);
+ memcpy(result + l, values.ni_namelist_val[i], n);
+ l += n;
+ if (i < values.ni_namelist_len - 1)
+ result[l++] = ',';
+ }
+ result[l] = '\0';
+ return_val = result;
+ break;
+ }
+
+ if (++depth >= NETINFO_MAX_DOMAIN_DEPTH) {
+ msg_warn("ni_open: domain depth limit");
+ break;
+ }
+ r = ni_open(domain, "..", &next_domain);
+ if (r != NI_OK) {
+ if (r != NI_FAILED)
+ msg_warn("ni_open `..': %d", r);
+ break;
+ }
+ ni_free(domain);
+ domain = next_domain;
+ }
+
+ ni_free(domain);
+
+ return return_val;
+}
+
+/* dict_ni_lookup - find table entry */
+
+static const char *dict_ni_lookup(DICT *dict, const char *key)
+{
+ DICT_NI *d = (DICT_NI *) dict;
+
+ return dict_ni_do_lookup(d->path, NETINFO_PROP_KEY,
+ key, NETINFO_PROP_VALUE);
+}
+
+/* dict_ni_update - add or update table entry (not!) */
+
+static void dict_ni_update(DICT *dict, const char *unused_name,
+ const char *unused_value)
+{
+ DICT_NI *d = (DICT_NI *) dict;
+
+ msg_fatal("dict_ni_update: unimplemented: update NetInfo directory %s",
+ d->path);
+}
+
+/* dict_ni_close - disassociate from NetInfo map */
+
+static void dict_ni_close(DICT *dict)
+{
+ DICT_NI *d = (DICT_NI *) dict;
+
+ myfree(d->path);
+ myfree((char *) d);
+}
+
+/* dict_ni_open - create association with NetInfo map */
+
+DICT *dict_ni_open(const char *path, int unused_flags, int dict_flags)
+{
+ DICT_NI *d = (void *) mymalloc(sizeof(*d));
+
+ d->dict.lookup = dict_ni_lookup;
+ d->dict.update = dict_ni_update;
+ d->dict.close = dict_ni_close;
+ d->dict.fd = -1;
+ d->dict.flags = dict_flags;
+ d->path = mystrdup(path);
+
+ return &d->dict;
+}
+
#endif
+#ifndef _DICT_NI_H_INCLUDED_
+#define _DICT_NI_H_INCLUDED_
+
+/*++
+/* NAME
+/* dict_ni 3h
+/* SUMMARY
+/* dictionary manager interface to NetInfo maps
+/* SYNOPSIS
+/* #include <dict_ni.h>
+/* DESCRIPTION
+/* .nf
+
/*
- * The NetInfo software is not bundled with IBM's public release. It will be
- * made available as contributed software from http://www.postfix.org/
+ * Utility library.
*/
+#include <dict.h>
+
+ /*
+ * External interface.
+ */
+extern DICT *dict_ni_open(const char *, int, int);
+
+/* AUTHOR(S)
+/* Pieter Schoenmakers
+/* Eindhoven University of Technology
+/* P.O. Box 513
+/* 5600 MB Eindhoven
+/* The Netherlands
+/*--*/
+
+#endif
/* SYNOPSIS
/* #include <dict_nis.h>
/*
-/* DICT *dict_nis_open(map, dummy)
+/* DICT *dict_nis_open(map, dummy, dict_flags)
/* const char *map;
/* int dummy;
+/* int dict_flags;
/* DESCRIPTION
/* dict_nis_open() makes the specified NIS map accessible via
/* the generic dictionary operations described in dict_open(3).
int flags; /* see below */
} DICT_NIS;
-#define DICT_NIS_TRY0NULL (1<<0)
-#define DICT_NIS_TRY1NULL (1<<1)
-
/*
* Class variables, so that multiple maps can share this info.
*/
* See if this NIS map was written with one null byte appended to key and
* value.
*/
- if (dict_nis->flags & DICT_NIS_TRY1NULL) {
+ if (dict_nis->flags & DICT_FLAG_TRY1NULL) {
err = yp_match(dict_nis_domain, dict_nis->map,
(void *) key, strlen(key) + 1,
&result, &result_len);
if (err == 0) {
- dict_nis->flags &= ~DICT_NIS_TRY0NULL;
+ dict_nis->flags &= ~DICT_FLAG_TRY0NULL;
return (result);
}
}
* See if this NIS map was written with no null byte appended to key and
* value. This should never be the case, but better play safe.
*/
- if (dict_nis->flags & DICT_NIS_TRY0NULL) {
+ if (dict_nis->flags & DICT_FLAG_TRY0NULL) {
err = yp_match(dict_nis_domain, dict_nis->map,
(void *) key, strlen(key),
&result, &result_len);
if (err == 0) {
- dict_nis->flags &= ~DICT_NIS_TRY1NULL;
+ dict_nis->flags &= ~DICT_FLAG_TRY1NULL;
if (buf == 0)
buf = vstring_alloc(10);
vstring_strncpy(buf, result, result_len);
/* dict_nis_open - open NIS map */
-DICT *dict_nis_open(const char *map, int unused_flags)
+DICT *dict_nis_open(const char *map, int unused_flags, int dict_flags)
{
DICT_NIS *dict_nis;
dict_nis->dict.close = dict_nis_close;
dict_nis->dict.fd = -1;
dict_nis->map = mystrdup(map);
- dict_nis->flags = (DICT_NIS_TRY1NULL | DICT_NIS_TRY0NULL);
+ dict_nis->dict.flags = dict_flags;
+ if ((dict_flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
+ dict_nis->dict.flags |= (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL);
if (dict_nis_domain == 0)
dict_nis_init();
return (&dict_nis->dict);
/*
* External interface.
*/
-extern DICT *dict_nis_open(const char *, int);
+extern DICT *dict_nis_open(const char *, int, int);
/* LICENSE
/* .ad
/* SYNOPSIS
/* #include <dict_nisplus.h>
/*
-/* DICT *dict_nisplus_open(map, dummy)
+/* DICT *dict_nisplus_open(map, dummy, dict_flags)
/* char *map;
/* int dummy;
+/* int dict_flags;
/* DESCRIPTION
/* dict_nisplus_open() makes the specified NIS+ map accessible via
/* the generic dictionary operations described in dict_open(3).
/* dict_nisplus_open - open NISPLUS map */
-DICT *dict_nisplus_open(const char *map, int unused_flags)
+DICT *dict_nisplus_open(const char *map, int unused_flags, int dict_flags)
{
DICT_NISPLUS *dict_nisplus;
dict_nisplus->dict.close = dict_nisplus_close;
dict_nisplus->dict.fd = -1;
dict_nisplus->map = mystrdup(map);
+ dict_nisplus->dict.flags = dict_flags;
return (&dict_nisplus->dict);
}
/*
* External interface.
*/
-extern DICT *dict_nisplus_open(const char *, int);
+extern DICT *dict_nisplus_open(const char *, int, int);
/* LICENSE
/* .ad
/* SYNOPSIS
/* #include <dict.h>
/*
-/* DICT *dict_open(dict_spec, flags)
+/* DICT *dict_open(dict_spec, open_flags, dict_flags)
/* const char *dict_spec;
-/* int flags;
+/* int open_flags;
+/* int dict_flags;
/*
-/* DICT *dict_open3(dict_type, dict_name, flags)
+/* DICT *dict_open3(dict_type, dict_name, open_flags, dict_flags)
/* const char *dict_type;
/* const char *dict_name;
-/* int flags;
+/* int open_flags;
+/* int dict_flags;
/*
/* void dict_put(dict, key, value)
/* DICT *dict;
/*
/* dict_open() takes a type:name pair that specifies a dictionary type
/* and dictionary name, opens the dictionary, and returns a dictionary
-/* handle. The \fIflags\fR arguments are as in open(2). The dictionary
-/* types are as follows:
+/* handle. The \fIopen_flags\fR arguments are as in open(2). The
+/* \fIdict_flags\fR are the bit-wise OR of zero or more of the following:
+/* .IP DICT_FLAG_DUP_WARN
+/* Warn about duplicate keys, if the underlying database does not
+/* support duplicate keys. The default is to terminate with a fatal
+/* error.
+/* .IP DICT_FLAG_DUP_IGNORE
+/* Ignore duplicate keys if the underlying database does not
+/* support duplicate keys. The default is to terminate with a fatal
+/* error.
+/* .PP
+/* The dictionary types are as follows:
/* .IP environ
/* The process environment array. The \fIdict_name\fR argument is ignored.
/* .IP dbm
/* LDAP ("light-weight" directory access protocol) database access.
/* .IP pcre
/* PERL-compatible regular expressions.
+/* .IP regexp
+/* POSIX-compatible regular expressions.
/* .PP
/* dict_open3() takes separate arguments for dictionary type and
/* name, but otherwise performs the same functions as dict_open().
#include <dict_ni.h>
#include <dict_ldap.h>
#include <dict_pcre.h>
+#include <dict_regexp.h>
#include <stringops.h>
#include <split_at.h>
*/
typedef struct {
char *type;
- struct DICT *(*open) (const char *, int);
+ struct DICT *(*open) (const char *, int, int);
} DICT_OPEN_INFO;
static DICT_OPEN_INFO dict_open_info[] = {
#endif
#ifdef HAS_PCRE
"pcre", dict_pcre_open,
+#endif
+#ifdef HAS_POSIX_REGEXP
+ "regexp", dict_regexp_open,
#endif
0,
};
/* dict_open - open dictionary */
-DICT *dict_open(const char *dict_spec, int flags)
+DICT *dict_open(const char *dict_spec, int open_flags, int dict_flags)
{
char *saved_dict_spec = mystrdup(dict_spec);
char *dict_name;
if ((dict_name = split_at(saved_dict_spec, ':')) == 0)
msg_fatal("open dictionary: need \"type:name\" form: %s", dict_spec);
- dict = dict_open3(saved_dict_spec, dict_name, flags);
+ dict = dict_open3(saved_dict_spec, dict_name, open_flags, dict_flags);
myfree(saved_dict_spec);
return (dict);
}
/* dict_open3 - open dictionary */
-DICT *dict_open3(const char *dict_type, const char *dict_name, int flags)
+DICT *dict_open3(const char *dict_type, const char *dict_name,
+ int open_flags, int dict_flags)
{
char *myname = "dict_open";
DICT_OPEN_INFO *dp;
for (dp = dict_open_info; dp->type; dp++) {
if (strcasecmp(dp->type, dict_type) == 0) {
- if ((dict = dp->open(dict_name, flags)) == 0)
+ if ((dict = dp->open(dict_name, open_flags, dict_flags)) == 0)
msg_fatal("opening %s:%s %m", dict_type, dict_name);
if (msg_verbose)
msg_info("%s: %s:%s", myname, dict_type, dict_name);
VSTRING *keybuf = vstring_alloc(1);
DICT *dict;
char *dict_name;
- int dict_flags;
+ int open_flags;
char *key;
const char *value;
if (argc != 3)
msg_fatal("usage: %s type:file read|write|create", argv[0]);
if (strcasecmp(argv[2], "create") == 0)
- dict_flags = O_CREAT | O_RDWR | O_TRUNC;
+ open_flags = O_CREAT | O_RDWR | O_TRUNC;
else if (strcasecmp(argv[2], "write") == 0)
- dict_flags = O_RDWR;
+ open_flags = O_RDWR;
else if (strcasecmp(argv[2], "read") == 0)
- dict_flags = O_RDONLY;
+ open_flags = O_RDONLY;
else
msg_fatal("unknown access mode: %s", argv[2]);
dict_name = argv[1];
- dict = dict_open(dict_name, dict_flags);
+ dict = dict_open(dict_name, open_flags, 0);
while (vstring_fgets_nonl(keybuf, VSTREAM_IN)) {
if ((key = strtok(vstring_str(keybuf), " =")) == 0)
continue;
/* SYNOPSIS
/* #include <dict_pcre.h>
/*
-/* DICT *dict_pcre_open(name, flags)
+/* DICT *dict_pcre_open(name, dummy, dict_flags)
/* const char *name;
-/* int flags;
+/* int dummy;
+/* int dict_flags;
/* DESCRIPTION
/* dict_pcre_open() opens the named file and compiles the contained
/* regular expressions.
/* The lookup interface will match only user@domain form addresses.
/* SEE ALSO
/* dict(3) generic dictionary manager
-/* LICENSE
-/* .ad
-/* .fi
-/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Andrew McNamara
/* andrewm@connect.com.au
dict_pcre->dict.close = dict_pcre_close;
dict_pcre->dict.fd = -1;
dict_pcre->map = mystrdup(map);
- dict_pcre->flags = 0;
+ dict_pcre->dict.flags = dict_flags;
dict_pcre->head = NULL;
if (dict_pcre_init == 0) {
- pcre_malloc = (void *(*)(size_t)) mymalloc;
- pcre_free = (void (*)(void *)) myfree;
+ pcre_malloc = (void *(*) (size_t)) mymalloc;
+ pcre_free = (void (*) (void *)) myfree;
dict_pcre_init = 1;
}
if ((map_fp = vstream_fopen(map, O_RDONLY, 0)) == 0) {
else
pcre_list->next = pl;
pcre_list = pl;
-}
+ }
-vstring_free(line_buffer);
-vstream_fclose(map_fp);
+ vstring_free(line_buffer);
+ vstream_fclose(map_fp);
-return (&dict_pcre->dict);
+ return (&dict_pcre->dict);
}
#endif /* HAS_PCRE */
/*
* External interface.
*/
-extern DICT *dict_pcre_open(const char *, int);
+extern DICT *dict_pcre_open(const char *, int, int);
/* LICENSE
/* .ad
--- /dev/null
+/*++
+/* NAME
+/* dict_regexp 3
+/* SUMMARY
+/* dictionary manager interface to REGEXP regular expression library
+/* SYNOPSIS
+/* #include <dict_regexp.h>
+/*
+/* DICT *dict_regexp_open(name, dummy, dict_flags)
+/* const char *name;
+/* int dummy;
+/* int dict_flags;
+/* DESCRIPTION
+/* dict_regexp_open() opens the named file and compiles the contained
+/* regular expressions.
+/*
+/* The lookup interface will match only user@domain form addresses.
+/* SEE ALSO
+/* dict(3) generic dictionary manager
+/* AUTHOR(S)
+/* LaMont Jones
+/* lamont@hp.com
+/*
+/* Based on PCRE dictionary contributed by Andrew McNamara
+/* andrewm@connect.com.au
+/* connect.com.au Pty. Ltd.
+/* Level 3, 213 Miller St
+/* North Sydney, NSW, Australia
+/*
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include "sys_defs.h"
+
+#ifdef HAS_POSIX_REGEXP
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <regex.h>
+
+/* Utility library. */
+
+#include "mymalloc.h"
+#include "msg.h"
+#include "safe.h"
+#include "vstream.h"
+#include "vstring.h"
+#include "stringops.h"
+#include "readline.h"
+#include "dict.h"
+#include "dict_regexp.h"
+#include "mac_parse.h"
+
+typedef struct dict_regexp_list {
+ struct dict_regexp_list *next; /* Next regexp in dict */
+ regex_t *expr[2]; /* The compiled pattern(s) */
+ char *replace; /* Replacement string */
+ int lineno; /* Source file line number */
+} DICT_REGEXP_RULE;
+
+typedef struct {
+ DICT dict; /* generic members */
+ char *map; /* map name */
+ int flags; /* unused at the moment */
+ regmatch_t *pmatch; /* Cut substrings */
+ int nmatch; /* number of elements in pmatch */
+ DICT_REGEXP_RULE *head; /* first rule */
+} DICT_REGEXP;
+
+/*
+ * Context for macro expansion callback.
+ */
+struct dict_regexp_context {
+ DICT_REGEXP *dict; /* the dictionary entry */
+ DICT_REGEXP_RULE *rule; /* the rule we matched */
+ VSTRING *buf; /* target string buffer */
+ const char *subject; /* str against which we match */
+};
+
+/*
+ * dict_regexp_update - not supported
+ */
+static void dict_regexp_update(DICT *dict, const char *unused_name,
+ const char *unused_value)
+{
+ DICT_REGEXP *dict_regexp = (DICT_REGEXP *) dict;
+
+ msg_fatal("dict_regexp_update: attempt to update regexp map %s",
+ dict_regexp->map);
+}
+
+/*
+ * Macro expansion callback - replace $0-${99} with strings cut from
+ * matched string.
+ */
+static void dict_regexp_action(int type, VSTRING *buf, char *ptr)
+{
+ struct dict_regexp_context *ctxt = (struct dict_regexp_context *) ptr;
+ DICT_REGEXP_RULE *rule = ctxt->rule;
+ DICT_REGEXP *dict = ctxt->dict;
+ int n;
+
+ if (type == MAC_PARSE_VARNAME) {
+ n = atoi(vstring_str(buf));
+ if (n >= dict->nmatch) {
+ msg_warn("regexp %s, line %d: replace index out of range",
+ dict->map, rule->lineno);
+ return;
+ }
+ if (dict->pmatch[n].rm_so < 0 ||
+ dict->pmatch[n].rm_so == dict->pmatch[n].rm_eo) {
+ return; /* empty string or not
+ * matched */
+ }
+ vstring_strncat(ctxt->buf, ctxt->subject + dict->pmatch[n].rm_so,
+ dict->pmatch[n].rm_eo - dict->pmatch[n].rm_so);
+ } else
+ /* Straight text - duplicate with no substitution */
+ vstring_strcat(ctxt->buf, vstring_str(buf));
+}
+
+/*
+ * Look up regexp dict and perform string substitution on matched
+ * strings.
+ */
+static const char *dict_regexp_lookup(DICT *dict, const char *name)
+{
+ DICT_REGEXP *dict_regexp = (DICT_REGEXP *) dict;
+ DICT_REGEXP_RULE *rule;
+ struct dict_regexp_context ctxt;
+ static VSTRING *buf;
+ char *at;
+ int error;
+
+ /* msg_info("dict_regexp_lookup: %s: %s", dict_regexp->map, name ); */
+
+ /*
+ * XXX Require user@domain, to defeat partial address matching for smtp
+ * access control, canonical and virtual mappings, and to prevent regexps
+ * from being used as alias databases because one might inadvertently
+ * copy "|command" or /file/name or :include: to the result.
+ */
+ if (name[0] == '@' || (at = strrchr(name, '@')) == 0 || at[1] == 0)
+ return (0);
+
+ /* Search for a matching expression */
+ for (rule = dict_regexp->head; rule; rule = rule->next) {
+ error = regexec(rule->expr[0], name, rule->expr[0]->re_nsub + 1,
+ dict_regexp->pmatch, 0);
+ if (!error) {
+ if (rule->expr[1]) {
+ error = regexec(rule->expr[1], name, rule->expr[1]->re_nsub + 1,
+ dict_regexp->pmatch + rule->expr[0]->re_nsub + 1, 0);
+ if (!error) {
+ continue;
+ } else if (error != REG_NOMATCH) {
+ char errbuf[256];
+
+ (void) regerror(error, rule->expr[1], errbuf, sizeof(errbuf));
+ msg_fatal("regexp map %s, line %d: %s.",
+ dict_regexp->map, rule->lineno, errbuf);
+ }
+ }
+
+ /*
+ * We found a match. Do some final initialization on the
+ * subexpression fields, and perform substitution on replacement
+ * string
+ */
+ if (!buf)
+ buf = vstring_alloc(10);
+ VSTRING_RESET(buf);
+ ctxt.buf = buf;
+ ctxt.subject = name;
+ ctxt.rule = rule;
+ ctxt.dict = dict_regexp;
+
+ mac_parse(rule->replace, dict_regexp_action, (char *) &ctxt);
+
+ VSTRING_TERMINATE(buf);
+ return (vstring_str(buf));
+ } else if (error && error != REG_NOMATCH) {
+ char errbuf[256];
+
+ (void) regerror(error, rule->expr[0], errbuf, sizeof(errbuf));
+ msg_fatal("regexp map %s, line %d: %s.",
+ dict_regexp->map, rule->lineno, errbuf);
+ return ((char *) 0);
+ }
+ }
+ return ((char *) 0);
+}
+
+/* dict_regexp_close - close regexp dictionary */
+
+static void dict_regexp_close(DICT *dict)
+{
+ DICT_REGEXP *dict_regexp = (DICT_REGEXP *) dict;
+ DICT_REGEXP_RULE *rule,
+ *next;
+ int i;
+
+ for (rule = dict_regexp->head; rule; rule = next) {
+ next = rule->next;
+ for (i = 0; i < 2; i++) {
+ if (rule->expr[i]) {
+ regfree(rule->expr[i]);
+ myfree((char *) rule->expr[i]);
+ }
+ }
+ myfree((char *) rule->replace);
+ myfree((char *) rule);
+ }
+ myfree((char *) dict_regexp);
+}
+
+static regex_t *dict_regexp_get_expr(int lineno, char **bufp, VSTREAM *map_fp)
+{
+ char *p = *bufp,
+ *regexp,
+ re_delim;
+ int re_options,
+ error;
+ regex_t *expr;
+
+ re_delim = *p++;
+ regexp = p;
+
+ /* Search for second delimiter, handling backslash escape */
+ while (*p) {
+ if (*p == '\\') {
+ if (p[1])
+ p++;
+ else
+ break;
+ } else if (*p == re_delim) {
+ break;
+ }
+ ++p;
+ }
+ if (!*p) {
+ msg_warn("%s, line %d: no closing regexp delimiter: %c",
+ VSTREAM_PATH(map_fp), lineno, re_delim);
+ return NULL;
+ }
+ *p++ = '\0'; /* Null term the regexp */
+
+ re_options = REG_EXTENDED | REG_ICASE;
+ while (*p) {
+ if (!*p || ISSPACE(*p) || (*p == '!' && p[1] == re_delim)) {
+ /* end of the regexp */
+ expr = (regex_t *) mymalloc(sizeof(*expr));
+ error = regcomp(expr, regexp, re_options);
+ if (error != 0) {
+ char errbuf[256];
+
+ (void) regerror(error, expr, errbuf, sizeof(errbuf));
+ msg_warn("%s, line %d: error in regexp: %s.",
+ VSTREAM_PATH(map_fp), lineno, errbuf);
+ myfree((char *) expr);
+ return NULL;
+ }
+ *bufp = p;
+ return expr;
+ } else {
+ switch (*p) {
+ case 'i':
+ re_options ^= REG_ICASE;
+ break;
+ case 'm':
+ re_options ^= REG_NEWLINE;
+ break;
+ case 'x':
+ re_options ^= REG_EXTENDED;
+ break;
+ default:
+ msg_warn("%s, line %d: unknown regexp option '%c'",
+ VSTREAM_PATH(map_fp), lineno, *p);
+ }
+ ++p;
+ }
+ }
+ return NULL;
+}
+
+static DICT_REGEXP_RULE *dict_regexp_parseline(int lineno, char *line, int *nsub, VSTREAM *map_fp)
+{
+ DICT_REGEXP_RULE *rule;
+ char *p,
+ re_delim;
+ regex_t *expr1,
+ *expr2;
+ int total_nsub;
+
+ p = line;
+ re_delim = *p;
+
+ expr1 = dict_regexp_get_expr(lineno, &p, map_fp);
+ if (!expr1) {
+ return NULL;
+ } else if (*p == '!' && p[1] == re_delim) {
+ p++;
+ expr2 = dict_regexp_get_expr(lineno, &p, map_fp);
+ if (!expr2) {
+ myfree((char *) expr1);
+ return NULL;
+ }
+ total_nsub = expr1->re_nsub + expr2->re_nsub + 2;
+ } else {
+ expr2 = NULL;
+ total_nsub = expr1->re_nsub + 1;
+ }
+ if (nsub)
+ *nsub = total_nsub;
+
+ if (!ISSPACE(*p)) {
+ msg_warn("%s, line %d: Too many expressions.",
+ VSTREAM_PATH(map_fp), lineno);
+ myfree((char *) expr1);
+ if (expr2)
+ myfree((char *) expr2);
+ return NULL;
+ }
+ rule = (DICT_REGEXP_RULE *) mymalloc(sizeof(DICT_REGEXP_RULE));
+
+ while (*p && ISSPACE(*p))
+ ++p;
+
+ if (!*p) {
+ msg_warn("%s, line %d: no replacement text: using empty string",
+ VSTREAM_PATH(map_fp), lineno);
+ p = "";
+ }
+ rule->expr[0] = expr1;
+ rule->expr[1] = expr2;
+ rule->replace = mystrdup(p);
+ rule->lineno = lineno;
+ return rule;
+}
+
+/*
+ * dict_regexp_open - load and compile a file containing regular expressions
+ */
+DICT *dict_regexp_open(const char *map, int unused_flags, int dict_flags)
+{
+ DICT_REGEXP *dict_regexp;
+ VSTREAM *map_fp;
+ VSTRING *line_buffer;
+ DICT_REGEXP_RULE *rule,
+ *last_rule = NULL;
+ int lineno = 0;
+ int max_nsub = 0;
+ int nsub;
+ char *p;
+
+ line_buffer = vstring_alloc(100);
+
+ dict_regexp = (DICT_REGEXP *) mymalloc(sizeof(*dict_regexp));
+ dict_regexp->dict.lookup = dict_regexp_lookup;
+ dict_regexp->dict.update = dict_regexp_update;
+ dict_regexp->dict.close = dict_regexp_close;
+ dict_regexp->dict.fd = -1;
+ dict_regexp->map = mystrdup(map);
+ dict_regexp->dict.flags = dict_flags;
+
+ if ((map_fp = vstream_fopen(map, O_RDONLY, 0)) == 0) {
+ msg_fatal("open %s: %m", map);
+ }
+ while (readline(line_buffer, map_fp, &lineno)) {
+ p = vstring_str(line_buffer);
+
+ if (*p == '#') /* Skip comments */
+ continue;
+
+ if (*p == 0) /* Skip blank lines */
+ continue;
+
+ rule = dict_regexp_parseline(lineno, p, &nsub, map_fp);
+ if (rule) {
+ if (nsub > max_nsub)
+ max_nsub = nsub;
+
+ if (last_rule == NULL)
+ dict_regexp->head = rule;
+ else
+ last_rule->next = rule;
+ last_rule = rule;
+ }
+ }
+ last_rule->next = NULL;
+
+ dict_regexp->pmatch = (regmatch_t *) mymalloc(sizeof(regmatch_t) * max_nsub);
+ dict_regexp->nmatch = max_nsub;
+
+ vstring_free(line_buffer);
+ vstream_fclose(map_fp);
+
+ return (&dict_regexp->dict);
+}
+
+#endif /* NO_POSIX_REGEXP */
--- /dev/null
+#ifndef _DICT_REGEXP_H_INCLUDED_
+#define _DICT_REGEXP_H_INCLUDED_
+
+/*++
+/* NAME
+/* dict_regexp 3h
+/* SUMMARY
+/* dictionary manager interface to REGEXP regular expression library
+/* SYNOPSIS
+/* #include <dict_regexp.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * Utility library.
+ */
+#include <dict.h>
+
+ /*
+ * External interface.
+ */
+extern DICT *dict_regexp_open(const char *, int, int);
+
+/* AUTHOR(S)
+/* LaMont Jones
+/* lamont@hp.com
+/*
+/* Based on PCRE dictionary contributed by Andrew McNamara
+/* andrewm@connect.com.au
+/* connect.com.au Pty. Ltd.
+/* Level 3, 213 Miller St
+/* North Sydney, NSW, Australia
+/*
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+#endif
/* SYNOPSIS
/* #include <dict_unix.h>
/*
-/* DICT *dict_unix_open(map, dummy)
+/* DICT *dict_unix_open(map, dummy, dict_flags)
/* const char *map;
/* int dummy;
+/* int dict_flags;
/* DESCRIPTION
/* dict_unix_open() makes the specified UNIX table accessible via
/* the generic dictionary operations described in dict_open(3).
/* dict_unix_open - open UNIX map */
-DICT *dict_unix_open(const char *map, int unused_flags)
+DICT *dict_unix_open(const char *map, int unused_flags, int dict_flags)
{
DICT_UNIX *dict_unix;
struct dict_unix_lookup {
dict_unix->dict.close = dict_unix_close;
dict_unix->dict.fd = -1;
dict_unix->map = mystrdup(map);
+ dict_unix->dict.flags = dict_flags;
return (&dict_unix->dict);
}
/*
* External interface.
*/
-extern DICT *dict_unix_open(const char *, int);
+extern DICT *dict_unix_open(const char *, int, int);
/* LICENSE
/* .ad
/*
- * The environ.c module from TCP Wrappers is not bundled with IBM's public
- * release. It will be made available as contributed software from
- * http://www.postfix.org/
+ * From: TCP Wrapper.
+ *
+ * Many systems have putenv() but no setenv(). Other systems have setenv() but
+ * no putenv() (MIPS). Still other systems have neither (NeXT). This is a
+ * re-implementation that hopefully ends all problems.
+ *
+ * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
*/
#include "sys_defs.h"
#ifdef MISSING_SETENV_PUTENV
-#error "This requires contributed software from http://www.postfix.org/"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+extern char **environ;
+
+static int addenv(char *); /* append entry to environment */
+static int allocated = 0; /* environ is, or is not, allocated */
+
+#define DO_CLOBBER 1
+
+/* namelength - determine length of name in "name=whatever" */
+
+static int namelength(const char *name)
+{
+ char *equal;
+
+ equal = strchr(name, '=');
+ return ((equal == 0) ? strlen(name) : (equal - name));
+}
+
+/* findenv - given name, locate name=value */
+
+static char **findenv(const char *name, int len)
+{
+ char **envp;
+
+ for (envp = environ; envp && *envp; envp++)
+ if (strncmp(name, *envp, len) == 0 && (*envp)[len] == '=')
+ return (envp);
+ return (0);
+}
+
+#if 0
+
+/* getenv - given name, locate value */
+
+char *getenv(const char *name)
+{
+ int len = namelength(name);
+ char **envp = findenv(name, len);
+
+ return (envp ? *envp + len + 1 : 0);
+}
+
+/* putenv - update or append environment (name,value) pair */
+
+int putenv(const char *nameval)
+{
+ char *equal = strchr(nameval, '=');
+ char *value = (equal ? equal : "");
+
+ return (setenv(nameval, value, DO_CLOBBER));
+}
+
+/* unsetenv - remove variable from environment */
+
+void unsetenv(const char *name)
+{
+ char **envp;
+
+ while ((envp = findenv(name, namelength(name))) != 0)
+ while (envp[0] = envp[1])
+ envp++;
+}
+
+#endif
+
+/* setenv - update or append environment (name,value) pair */
+
+int setenv(const char *name, const char *value, int clobber)
+{
+ char *destination;
+ char **envp;
+ int l_name; /* length of name part */
+ unsigned int l_nameval; /* length of name=value */
+
+ /* Permit name= and =value. */
+
+ l_name = namelength(name);
+ envp = findenv(name, l_name);
+ if (envp != 0 && clobber == 0)
+ return (0);
+ if (*value == '=')
+ value++;
+ l_nameval = l_name + strlen(value) + 1;
+
+ /*
+ * Use available memory if the old value is long enough. Never free an
+ * old name=value entry because it may not be allocated.
+ */
+
+ destination = (envp != 0 && strlen(*envp) >= l_nameval) ?
+ *envp : malloc(l_nameval + 1);
+ if (destination == 0)
+ return (-1);
+ strncpy(destination, name, l_name);
+ destination[l_name] = '=';
+ strcpy(destination + l_name + 1, value);
+ return ((envp == 0) ? addenv(destination) : (*envp = destination, 0));
+}
+
+/* cmalloc - malloc and copy block of memory */
+
+static char *cmalloc(int new_len, char *old, int old_len)
+{
+ char *new = malloc(new_len);
+
+ if (new != 0)
+ memcpy(new, old, old_len);
+ return (new);
+}
+
+/* addenv - append environment entry */
+
+static int addenv(char *nameval)
+{
+ char **envp;
+ int n_used; /* number of environment entries */
+ int l_used; /* bytes used excl. terminator */
+ int l_need; /* bytes needed incl. terminator */
+
+ for (envp = environ; envp && *envp; envp++)
+ /* void */ ;
+ n_used = envp - environ;
+ l_used = n_used * sizeof(*envp);
+ l_need = l_used + 2 * sizeof(*envp);
+
+ envp = allocated ?
+ (char **) realloc((char *) environ, l_need) :
+ (char **) cmalloc(l_need, (char *) environ, l_used);
+ if (envp == 0) {
+ return (-1);
+ } else {
+ allocated = 1;
+ environ = envp;
+ environ[n_used++] = nameval; /* add new entry */
+ environ[n_used] = 0; /* terminate list */
+ return (0);
+ }
+}
+
#endif
} else if (strchr(pattern, ':') != 0) { /* type:table */
for (cp = pattern; *cp == '!'; cp++)
/* void */ ;
- dict_register(pattern, dict_open(pattern, 0));
+ dict_register(pattern, dict_open(pattern, 0, 0));
argv_add(list, pattern, (char *) 0);
} else { /* other pattern */
argv_add(list, pattern, (char *) 0);
- /*
- * The NETXSTEP and OPENSTEP software is not bundled with IBM's public
- * release. It will be made available as contributed software from
- * http://www.postfix.org/
- */
+/*++
+/* NAME
+/* posix_signals 3
+/* SUMMARY
+/* POSIX signal handling compatibility
+/* SYNOPSIS
+/* #include <posix_signals.h>
+/*
+/* int sigemptyset(m)
+/* sigset_t *m;
+/*
+/* int sigaddset(set, signum)
+/* sigset_t *set;
+/* int signum;
+/*
+/* int sigprocmask(how, set, old)
+/* int how;
+/* sigset_t *set;
+/* sigset_t *old;
+/*
+/* int sigaction(sig, act, oact)
+/* int sig;
+/* struct sigaction *act;
+/* struct sigaction *oact;
+/* DESCRIPTION
+/* These routines emulate the POSIX signal handling interface.
+/* AUTHOR(S)
+/* Pieter Schoenmakers
+/* Eindhoven University of Technology
+/* P.O. Box 513
+/* 5600 MB Eindhoven
+/* The Netherlands
+/*--*/
+
+/* System library. */
+
#include "sys_defs.h"
+#include <signal.h>
+#include <errno.h>
+
+/* Utility library.*/
+
+#include "posix_signals.h"
#ifdef MISSING_SIGSET_T
-#error "This requires contributed software from http://www.postfix.org/"
+
+int sigemptyset(sigset_t *m)
+{
+ return *m = 0;
+}
+
+int sigaddset(sigset_t *set, int signum)
+{
+ *set |= sigmask(signum);
+ return 0;
+}
+
+int sigprocmask(int how, sigset_t *set, sigset_t *old)
+{
+ int previous;
+
+ if (how == SIG_BLOCK)
+ previous = sigblock(*set);
+ else if (how == SIG_SETMASK)
+ previous = sigsetmask(*set);
+ else if (how == SIG_UNBLOCK) {
+ int m = sigblock(0);
+
+ previous = sigsetmask(m & ~*set);
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (old)
+ *old = previous;
+ return 0;
+}
+
#endif
#ifdef MISSING_SIGACTION
-#error "This requires contributed software from http://www.postfix.org/"
-#endif
+static struct sigaction actions[NSIG] = {};
+
+static int sighandle(int signum)
+{
+ if (signum == SIGCHLD) {
+ /* XXX If the child is just stopped, don't invoke the handler. */
+ }
+ actions[signum].sa_handler(signum);
+}
+
+int sigaction(int sig, struct sigaction *act, struct sigaction *oact)
+{
+ static int initialized = 0;
+
+ if (!initialized) {
+ int i;
+
+ for (i = 0; i < NSIG; i++)
+ actions[i].sa_handler = SIG_DFL;
+ initialized = 1;
+ }
+ if (sig <= 0 || sig >= NSIG) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (oact)
+ *oact = actions[sig];
+
+ {
+ struct sigvec mine = {
+ sighandle, act->sa_mask,
+ act->sa_flags & SA_RESTART ? SV_INTERRUPT : 0
+ };
+
+ if (sigvec(sig, &mine, NULL))
+ return -1;
+ }
+
+ actions[sig] = *act;
+ return 0;
+}
+
+#endif
+#ifndef _POSIX_SIGNALS_H_INCLUDED_
+#define _POSIX_SIGNALS_H_INCLUDED_
+/*++
+/* NAME
+/* posix_signals 3h
+/* SUMMARY
+/* POSIX signal handling compatibility
+/* SYNOPSIS
+/* #include <posix_signals.h>
+/* DESCRIPTION
+/* .nf
+
/*
- * The NETXSTEP and OPENSTEP software is not bundled with IBM's public
- * release. It will be made available as contributed software from
- * http://www.postfix.org/
+ * Compatibility interface.
*/
+
+#ifdef MISSING_SIGSET_T
+
+typedef int sigset_t;
+
+enum {
+ SIG_BLOCK,
+ SIG_UNBLOCK,
+ SIG_SETMASK
+};
+
+extern int sigemptyset(sigset_t *);
+extern int sigaddset(sigset_t *, int);
+extern int sigprocmask(int, sigset_t *, sigset_t *);
+
+#endif
+
+#ifdef MISSING_SIGACTION
+
+struct sigaction {
+ void (*sa_handler) ();
+ sigset_t sa_mask;
+ int sa_flags;
+};
+
+ /* Possible values for sa_flags. Or them to set multiple. */
+enum {
+ SA_RESTART,
+ SA_NOCLDSTOP = 4 /* drop the = 4. */
+};
+
+extern int sigaction(int, struct sigaction *, struct sigaction *);
+
+#endif
+
+/* AUTHOR(S)
+/* Pieter Schoenmakers
+/* Eindhoven University of Technology
+/* P.O. Box 513
+/* 5600 MB Eindhoven
+/* The Netherlands
+/*--*/
+
+#endif
#define ROOT_PATH "/bin:/usr/bin:/sbin:/usr/sbin"
#define USE_STATFS
#define STATFS_IN_SYS_MOUNT_H
+#define HAS_POSIX_REGEXP
#endif
#if defined(OPENBSD2)
#define STATFS_IN_SYS_VFS_H
#define UNIX_DOMAIN_CONNECT_BLOCKS_FOR_ACCEPT
#define PREPEND_PLUS_TO_OPTSTRING
+#define HAS_POSIX_REGEXP
#endif
/*