]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.9-20120108
authorWietse Venema <wietse@porcupine.org>
Sun, 8 Jan 2012 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:37:53 +0000 (06:37 +0000)
110 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/README_FILES/DATABASE_README
postfix/WISHLIST
postfix/html/DATABASE_README.html
postfix/html/postalias.1.html
postfix/html/postconf.1.html
postfix/html/postmap.1.html
postfix/man/man1/postalias.1
postfix/man/man1/postconf.1
postfix/man/man1/postmap.1
postfix/proto/DATABASE_README.html
postfix/src/cleanup/Makefile.in
postfix/src/cleanup/cleanup_map11.c
postfix/src/cleanup/cleanup_map1n.c
postfix/src/cleanup/cleanup_milter.ref1
postfix/src/cleanup/cleanup_milter.ref12
postfix/src/cleanup/cleanup_milter.ref13a
postfix/src/cleanup/cleanup_milter.ref3
postfix/src/cleanup/cleanup_milter.ref4
postfix/src/flush/Makefile.in
postfix/src/global/Makefile.in
postfix/src/global/addr_match_list.c
postfix/src/global/db_common.c
postfix/src/global/dict_ldap.c
postfix/src/global/dict_memcache.c
postfix/src/global/dict_mysql.c
postfix/src/global/dict_pgsql.c
postfix/src/global/dict_proxy.c
postfix/src/global/dict_sqlite.c
postfix/src/global/domain_list.c
postfix/src/global/flush_clnt.c
postfix/src/global/mail_addr_find.c
postfix/src/global/mail_addr_map.c
postfix/src/global/mail_conf.c
postfix/src/global/mail_version.h
postfix/src/global/maps.c
postfix/src/global/maps.h
postfix/src/global/match_parent_style.h
postfix/src/global/mkmap.h
postfix/src/global/mkmap_fail.c [new file with mode: 0644]
postfix/src/global/mkmap_open.c
postfix/src/global/namadr_list.c
postfix/src/global/resolve_local.c
postfix/src/global/server_acl.c
postfix/src/global/string_list.c
postfix/src/local/alias.c
postfix/src/local/bounce_workaround.c
postfix/src/local/mailbox.c
postfix/src/local/unknown.c
postfix/src/postalias/Makefile.in
postfix/src/postalias/aliases [new file with mode: 0644]
postfix/src/postalias/fail_test.in [new file with mode: 0644]
postfix/src/postalias/fail_test.ref [new file with mode: 0644]
postfix/src/postalias/postalias.c
postfix/src/postconf/postconf.c
postfix/src/postconf/postconf_main.c
postfix/src/postmap/Makefile.in
postfix/src/postmap/aliases [new file with mode: 0644]
postfix/src/postmap/fail_test.in [new file with mode: 0644]
postfix/src/postmap/fail_test.ref [new file with mode: 0644]
postfix/src/postmap/postmap.c
postfix/src/postscreen/Makefile.in
postfix/src/postscreen/postscreen_smtpd.c
postfix/src/proxymap/proxymap.c
postfix/src/qmqpd/Makefile.in
postfix/src/qmqpd/qmqpd.c
postfix/src/smtp/Makefile.in
postfix/src/smtp/smtp_chat.c
postfix/src/smtp/smtp_map11.c
postfix/src/smtp/smtp_sasl_auth_cache.c
postfix/src/smtpd/Makefile.in
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd_check.c
postfix/src/trivial-rewrite/Makefile.in
postfix/src/trivial-rewrite/resolve.c
postfix/src/trivial-rewrite/transport.c
postfix/src/util/Makefile.in
postfix/src/util/dict.c
postfix/src/util/dict.h
postfix/src/util/dict_alloc.c
postfix/src/util/dict_cache.c
postfix/src/util/dict_cache.h
postfix/src/util/dict_cdb.c
postfix/src/util/dict_cidr.c
postfix/src/util/dict_db.c
postfix/src/util/dict_dbm.c
postfix/src/util/dict_debug.c
postfix/src/util/dict_env.c
postfix/src/util/dict_fail.c
postfix/src/util/dict_ht.c
postfix/src/util/dict_ni.c
postfix/src/util/dict_nis.c
postfix/src/util/dict_nisplus.c
postfix/src/util/dict_open.c
postfix/src/util/dict_pcre.c
postfix/src/util/dict_regexp.c
postfix/src/util/dict_sdbm.c
postfix/src/util/dict_static.c
postfix/src/util/dict_tcp.c
postfix/src/util/dict_test.c
postfix/src/util/dict_thash.c
postfix/src/util/dict_unix.c
postfix/src/util/match_list.c
postfix/src/util/match_list.h
postfix/src/util/match_ops.c
postfix/src/util/match_ops.h [deleted file]
postfix/src/util/msg.h
postfix/src/util/msg_rate_delay.c [new file with mode: 0644]
postfix/src/virtual/mailbox.c

index 097a67a2cfa475a95fa47f9ced5c47a30109e80a..9e679a2cab22a8dc177ad155fb93be2affc42119 100644 (file)
 -TDICT_STACK
 -TDICT_TCP
 -TDICT_TEXT
+-TDICT_THASH
 -TDICT_UNIX
 -TDNS_FIXED
 -TDNS_REPLY
 -Tsfsistat
 -Tsize_t
 -Tssize_t
+-Ttime_t
index 48365be9987444773fee4e59d5bfa2b353bb1bea..d2ae3b1ef76f810bce847343bba347a682907149 100644 (file)
@@ -17432,11 +17432,36 @@ Apologies for any names omitted.
        namadr_list.c, trivial-rewrite/resolve.c, smtpd/smtpd.c,
        smtpd/smtpd_check.c, global/flush_clnt.c, flush/flush.c.
 
-20111226
+20111224
+
+       Cleanup: eliminated the global dict_errno variable that
+       made error reporting convenient but not necessarily precise.
+       This was a straightforward change except in the few modules
+       that propagate errors from one dictionary API to another:
+       dict_cache.c, dict_debug.c, maps.c, dict_memcache.c.  Files:
+       src/cleanup/cleanup_map11.c, src/cleanup/cleanup_map1n.c,
+       src/global/addr_match_list.c, src/global/dict_ldap.c,
+       src/global/dict_memcache.c, src/global/dict_mysql.c,
+       src/global/dict_pgsql.c, src/global/dict_proxy.c,
+       src/global/dict_sqlite.c, src/global/domain_list.c,
+       src/global/flush_clnt.c, src/global/mail_addr_find.c,
+       src/global/mail_addr_map.c, src/global/maps.c, src/global/maps.h,
+       src/global/match_parent_style.h, src/global/namadr_list.c,
+       src/global/resolve_local.c, src/global/resolve_local.h,
+       src/global/server_acl.c, src/global/string_list.c,
+       src/local/alias.c, src/local/bounce_workaround.c,
+       src/local/mailbox.c, src/local/unknown.c, src/proxymap/proxymap.c,
+       src/qmqpd/qmqpd.c, src/smtp/smtp_map11.c, src/smtpd/smtpd_check.c,
+       src/trivial-rewrite/resolve.c, src/trivial-rewrite/transport.c,
+       src/util/dict.h, src/util/dict_alloc.c, src/util/dict_cache.c,
+       src/util/dict_cidr.c, src/util/dict_db.c, src/util/dict_debug.c,
+       src/util/dict_env.c, src/util/dict_fail.c, src/util/dict_ht.c,
+       src/util/dict_pcre.c, src/util/dict_regexp.c,
+       src/util/dict_static.c, src/util/dict_tcp.c, src/util/dict_test.c,
+       src/util/dict_thash.c, src/util/dict_unix.c, src/util/match_list.c,
+       src/util/match_list.h, src/util/match_ops.c, src/virtual/mailbox.c.
 
-       Cleanup: reset the global dict_errno flag before table
-       lookup, to avoid false alarms about table lookup errors.
-       Files: util/dict_thash.c, global/dict_sqlite.c, global.maps.c.
+20111226
 
        Bugfix (introduced 20110426): after lookup error with
        mailbox_transport_maps, mailbox_command_maps or
@@ -17452,3 +17477,25 @@ Apologies for any names omitted.
        master/master_ent.c, master/master_vars.c, postscreen/postscreen.c,
        qmqpd/qmqpd.c, smtp/smtp_connect.c, smtpd/smtpd.c,
        util/inet_proto.c.
+
+20120107
+
+       Workaround: degrade gracefully when the "domain" feature
+       of LDAP, *SQL and memcache databases has a table lookup
+       problem.  Files: global/db_common.c, global/dict_ldap.c,
+       global/dict*sql*.c, global/dict_memcache.c.
+
+       Cleanup: fixed memcache client error handling for things
+       that never happen.  global/dict_memcache.c.
+
+       Future proofing: prepare postmap/postalias error logging
+       for future changes to database code. Files: postalias/postalias.c,
+       postmap/postmap.c.
+
+20120108
+
+       Cleanup: the postscreen(8) and verify(8) cache managers log
+       warnings at a reduced rate of one per second per cache
+       operation, to avoid logging large numbers of warnings about
+       a problem with low-value information. File: util/msg_rate_delay.c,
+       util/dict_cache.c.
index 4353752c62add1096d477fc41d425b7c9e567397..231e426c8cd95b9285394add06db4846236cd23d 100644 (file)
@@ -199,9 +199,8 @@ To find out what database types your Postfix system supports, use the "p\bpo\bos\bs
         The UNIX process environment array. The lookup key is the variable
         name. The lookup table name in "environ:table" is ignored.
     f\bfa\bai\bil\bl (read-write)
-        A table that reliably fails all requests. The lookup table name
-        provides the internal error result code. This table exists to simplify
-        Postfix error tests.
+        A table that reliably fails all requests. The lookup table name is used
+        for logging only. This table exists to simplify Postfix error tests.
     h\bha\bas\bsh\bh
         An indexed file type based on hashing. This is available only on
         systems with support for Berkeley DB databases. Database files are
index e12f4dc59b5238f9d1ed518952995ac324c2809d..c201dae89bb888392fda4d050ec3ce8a969104f5 100644 (file)
@@ -4,19 +4,16 @@ Wish list:
 
        Remove this file from the stable release.
 
-       limits on attribute string length in IPC protocols. 10-20KB
-       seems OK. We could start with limits enabled only in proxymap.
+       Things to do after the stable release:
+
+       Before proxymap can be exposed to the network to share,
+       e.g., postscreen or verify caches, need to enforce limits
+       on attribute string length in IPC protocols.  10-20KB seems
+       OK. The VSTREAM library already supports read/write deadlines.
 
        move flush_init() etc. from defer service clients to the
        bounce daemon?
 
-       Is it practical to move errors from global dict_errno
-       to lookuphandle->dict_errno?
-
-       Either make all void dict_* operations return an error code,
-       or require that they reset dict_errno on entry, either exit
-       with a fatal error or set dict_errno on error.
-
        multi_connect() function that takes a list of inet:host:port
        and/or unix:pathname specs, with an explicit "inet" prefix
        argument to handle applications that use host:port only.
@@ -24,16 +21,14 @@ Wish list:
        client, dovecot client, and other.
 
        dict_memcache: treat "bad" key as cache miss, i.e.  read/write
-       the database as if the cache did not exist. This does not
-       work because most Postfix maps (virtual, canonical, access,
-       transport, ...) also don't support spaces in keys.
+       the backup database as if the cache did not exist. This
+       does not help because most Postfix maps (virtual, canonical,
+       access, transport, ...) also don't support spaces in keys.
 
        postscreen: keep the cache open after "postfix reload" when
        it is remote (type memcache: or proxy:). This does not work
        because memcache can use a non-proxied file as backup).
 
-       Things to do after the stable release:
-
        What is the feasibility of adding an mta_name (personality)
        attribute that is propagated via queue files and delivery
        agent requests? It would default to myhostname.
@@ -116,12 +111,6 @@ Wish list:
        into doubles (converting only some leads to a documentation
        nightmare).
 
-       postscreen: wait for DNS completion after early HANGUP and
-       log DNSBL results. If the client was still waiting for the
-       PREGREET timer, just flag the PREGREET test as (done, not
-       passed).  If the client was not waiting for the PREGREET
-       timer, just wait until DNSBL lookup (if any) completes.
-
        Address verify cache: allow a negative cache "refresh"
        result to purge a "positive" cache entry in some safe manner.
        Currently, the negative cache "refresh" result is discarded,
index 1beb1c89805bb05e354db27f81de77d7c2950e2a..9ce2676b5b54cfb1e361563b289e19ee7b4f1646 100644 (file)
@@ -295,8 +295,8 @@ variable name. The lookup table name in "environ:table" is ignored.
 <dt> <b>fail</b> (read-write) </dt>
 
 <dd> A table that reliably fails all requests. The lookup table
-name provides the internal error result code. This table exists to
-simplify Postfix error tests. </dd>
+name is used for logging only. This table exists to simplify Postfix
+error tests. </dd>
 
 <dt> <b>hash</b> </dt>
 
index e78cade273c956904cc057299a1bcd5d8aca8589..10abcbe5a3de30868551017cabe3702422fa22fc 100644 (file)
@@ -147,29 +147,34 @@ POSTALIAS(1)                                                      POSTALIAS(1)
                      <i>file</i><b>_</b><i>name</i><b>.db</b>.  This is available on  systems
                      with support for <b>db</b> databases.
 
-              <b>sdbm</b>   The  output  consists  of  two  files, named
-                     <i>file</i><b>_</b><i>name</i><b>.pag</b> and  <i>file</i><b>_</b><i>name</i><b>.dir</b>.   This  is
-                     available  on  systems with support for <b>sdbm</b>
+              <b>fail</b>   A  table  that  reliably fails all requests.
+                     The lookup table name is  used  for  logging
+                     only.  This table exists to simplify Postfix
+                     error tests.
+
+              <b>sdbm</b>   The output  consists  of  two  files,  named
+                     <i>file</i><b>_</b><i>name</i><b>.pag</b>  and  <i>file</i><b>_</b><i>name</i><b>.dir</b>.   This is
+                     available on systems with support  for  <b>sdbm</b>
                      databases.
 
-              When no <i>file</i><b>_</b><i>type</i> is specified, the  software  uses
-              the  database  type specified via the <b><a href="postconf.5.html#default_database_type">default_data</a>-</b>
+              When  no  <i>file</i><b>_</b><i>type</i> is specified, the software uses
+              the database type specified via  the  <b><a href="postconf.5.html#default_database_type">default_data</a>-</b>
               <b><a href="postconf.5.html#default_database_type">base_type</a></b>  configuration  parameter.   The  default
-              value  for this parameter depends on the host envi-
+              value for this parameter depends on the host  envi-
               ronment.
 
        <i>file</i><b>_</b><i>name</i>
-              The name of the alias  database  source  file  when
+              The  name  of  the  alias database source file when
               creating a database.
 
 <b>DIAGNOSTICS</b>
-       Problems  are  logged  to the standard error stream and to
-       <b>syslogd</b>(8).   No  output  means  that  no  problems   were
-       detected.  Duplicate  entries  are skipped and are flagged
+       Problems are logged to the standard error  stream  and  to
+       <b>syslogd</b>(8).    No  output  means  that  no  problems  were
+       detected. Duplicate entries are skipped  and  are  flagged
        with a warning.
 
-       <a href="postalias.1.html"><b>postalias</b>(1)</a> terminates with zero exit status in  case  of
-       success  (including  successful "<b>postalias -q</b>" lookup) and
+       <a href="postalias.1.html"><b>postalias</b>(1)</a>  terminates  with zero exit status in case of
+       success (including successful "<b>postalias -q</b>"  lookup)  and
        terminates with non-zero exit status in case of failure.
 
 <b>ENVIRONMENT</b>
@@ -180,26 +185,26 @@ POSTALIAS(1)                                                      POSTALIAS(1)
               Enable verbose logging for debugging purposes.
 
 <b>CONFIGURATION PARAMETERS</b>
-       The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are  especially  relevant
+       The  following  <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant
        to this program.
 
-       The  text  below  provides  only  a parameter summary. See
+       The text below provides  only  a  parameter  summary.  See
        <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
 
        <b><a href="postconf.5.html#alias_database">alias_database</a> (see 'postconf -d' output)</b>
-              The alias databases for <a href="local.8.html"><b>local</b>(8)</a> delivery that  are
+              The  alias databases for <a href="local.8.html"><b>local</b>(8)</a> delivery that are
               updated with "<b>newaliases</b>" or with "<b>sendmail -bi</b>".
 
        <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
-              The  default  location  of  the Postfix <a href="postconf.5.html">main.cf</a> and
+              The default location of  the  Postfix  <a href="postconf.5.html">main.cf</a>  and
               <a href="master.5.html">master.cf</a> configuration files.
 
        <b><a href="postconf.5.html#berkeley_db_create_buffer_size">berkeley_db_create_buffer_size</a> (16777216)</b>
-              The per-table I/O buffer  size  for  programs  that
+              The  per-table  I/O  buffer  size for programs that
               create Berkeley DB hash or btree tables.
 
        <b><a href="postconf.5.html#berkeley_db_read_buffer_size">berkeley_db_read_buffer_size</a> (131072)</b>
-              The  per-table  I/O  buffer  size for programs that
+              The per-table I/O buffer  size  for  programs  that
               read Berkeley DB hash or btree tables.
 
        <b><a href="postconf.5.html#default_database_type">default_database_type</a> (see 'postconf -d' output)</b>
@@ -210,8 +215,8 @@ POSTALIAS(1)                                                      POSTALIAS(1)
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
-              The  mail  system  name  that  is  prepended to the
-              process name in syslog  records,  so  that  "smtpd"
+              The mail system  name  that  is  prepended  to  the
+              process  name  in  syslog  records, so that "smtpd"
               becomes, for example, "postfix/smtpd".
 
 <b>STANDARDS</b>
@@ -230,7 +235,7 @@ POSTALIAS(1)                                                      POSTALIAS(1)
        <a href="DATABASE_README.html">DATABASE_README</a>, Postfix lookup table overview
 
 <b>LICENSE</b>
-       The Secure Mailer license must be  distributed  with  this
+       The  Secure  Mailer  license must be distributed with this
        software.
 
 <b>AUTHOR(S)</b>
index 63d1483e5842edf7dddaa08a4a059ce6a6867871..350cb86a8722a4b6a718ec7729d06ac8d6bf41b0 100644 (file)
@@ -182,9 +182,9 @@ POSTCONF(1)                                                        POSTCONF(1)
                      this useful someday.
 
               <b>fail</b>   A table that reliably  fails  all  requests.
-                     The  lookup table name provides the internal
-                     error result code. This table exists to sim-
-                     plify Postfix error tests.
+                     The  lookup  table name is used for logging.
+                     This table exists to simplify Postfix  error
+                     tests.
 
               <b>hash</b>   An indexed file type based on hashing.  This
                      is available on  systems  with  support  for
index 123536ceaf1ebcfc3429c0f7fb1f66e7f7259256..c414c46bfae5854acd90feabfa341c2ca45c22d8 100644 (file)
@@ -207,27 +207,32 @@ POSTMAP(1)                                                          POSTMAP(1)
                      <i>file</i><b>_</b><i>name</i><b>.db</b>.  This is available on  systems
                      with support for <b>db</b> databases.
 
-              <b>sdbm</b>   The  output  consists  of  two  files, named
-                     <i>file</i><b>_</b><i>name</i><b>.pag</b> and  <i>file</i><b>_</b><i>name</i><b>.dir</b>.   This  is
-                     available  on  systems with support for <b>sdbm</b>
+              <b>fail</b>   A  table  that  reliably fails all requests.
+                     The lookup table name is  used  for  logging
+                     only.  This table exists to simplify Postfix
+                     error tests.
+
+              <b>sdbm</b>   The output  consists  of  two  files,  named
+                     <i>file</i><b>_</b><i>name</i><b>.pag</b>  and  <i>file</i><b>_</b><i>name</i><b>.dir</b>.   This is
+                     available on systems with support  for  <b>sdbm</b>
                      databases.
 
-              When no <i>file</i><b>_</b><i>type</i> is specified, the  software  uses
-              the  database  type specified via the <b><a href="postconf.5.html#default_database_type">default_data</a>-</b>
+              When  no  <i>file</i><b>_</b><i>type</i> is specified, the software uses
+              the database type specified via  the  <b><a href="postconf.5.html#default_database_type">default_data</a>-</b>
               <b><a href="postconf.5.html#default_database_type">base_type</a></b> configuration parameter.
 
        <i>file</i><b>_</b><i>name</i>
-              The name of  the  lookup  table  source  file  when
+              The  name  of  the  lookup  table  source file when
               rebuilding a database.
 
 <b>DIAGNOSTICS</b>
-       Problems  are  logged  to the standard error stream and to
-       <b>syslogd</b>(8).   No  output  means  that  no  problems   were
-       detected.  Duplicate  entries  are skipped and are flagged
+       Problems are logged to the standard error  stream  and  to
+       <b>syslogd</b>(8).    No  output  means  that  no  problems  were
+       detected. Duplicate entries are skipped  and  are  flagged
        with a warning.
 
-       <a href="postmap.1.html"><b>postmap</b>(1)</a> terminates with zero exit  status  in  case  of
-       success  (including  successful  "<b>postmap  -q</b>" lookup) and
+       <a href="postmap.1.html"><b>postmap</b>(1)</a>  terminates  with  zero  exit status in case of
+       success (including successful  "<b>postmap  -q</b>"  lookup)  and
        terminates with non-zero exit status in case of failure.
 
 <b>ENVIRONMENT</b>
@@ -238,21 +243,21 @@ POSTMAP(1)                                                          POSTMAP(1)
               Enable verbose logging for debugging purposes.
 
 <b>CONFIGURATION PARAMETERS</b>
-       The following <a href="postconf.5.html"><b>main.cf</b></a> parameters are  especially  relevant
+       The  following  <a href="postconf.5.html"><b>main.cf</b></a> parameters are especially relevant
        to this program.  The text below provides only a parameter
-       summary. See <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including  exam-
+       summary.  See <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including exam-
        ples.
 
        <b><a href="postconf.5.html#berkeley_db_create_buffer_size">berkeley_db_create_buffer_size</a> (16777216)</b>
-              The  per-table  I/O  buffer  size for programs that
+              The per-table I/O buffer  size  for  programs  that
               create Berkeley DB hash or btree tables.
 
        <b><a href="postconf.5.html#berkeley_db_read_buffer_size">berkeley_db_read_buffer_size</a> (131072)</b>
-              The per-table I/O buffer  size  for  programs  that
+              The  per-table  I/O  buffer  size for programs that
               read Berkeley DB hash or btree tables.
 
        <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
-              The  default  location  of  the Postfix <a href="postconf.5.html">main.cf</a> and
+              The default location of  the  Postfix  <a href="postconf.5.html">main.cf</a>  and
               <a href="master.5.html">master.cf</a> configuration files.
 
        <b><a href="postconf.5.html#default_database_type">default_database_type</a> (see 'postconf -d' output)</b>
@@ -263,8 +268,8 @@ POSTMAP(1)                                                          POSTMAP(1)
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
-              The  mail  system  name  that  is  prepended to the
-              process name in syslog  records,  so  that  "smtpd"
+              The mail system  name  that  is  prepended  to  the
+              process  name  in  syslog  records, so that "smtpd"
               becomes, for example, "postfix/smtpd".
 
 <b>SEE ALSO</b>
@@ -277,7 +282,7 @@ POSTMAP(1)                                                          POSTMAP(1)
        <a href="DATABASE_README.html">DATABASE_README</a>, Postfix lookup table overview
 
 <b>LICENSE</b>
-       The Secure Mailer license must be  distributed  with  this
+       The  Secure  Mailer  license must be distributed with this
        software.
 
 <b>AUTHOR(S)</b>
index 8e86b8b869977c35dd911914f0c296fd704f2a7a..9dda165f6474f431692d220bc873d210dc4e5937 100644 (file)
@@ -127,6 +127,10 @@ This is available on systems with support for \fBdbm\fR databases.
 .IP \fBhash\fR
 The output is a hashed file, named \fIfile_name\fB.db\fR.
 This is available on systems with support for \fBdb\fR databases.
+.IP \fBfail\fR
+A table that reliably fails all requests. The lookup table
+name is used for logging only. This table exists to simplify
+Postfix error tests.
 .IP \fBsdbm\fR
 The output consists of two files, named \fIfile_name\fB.pag\fR and
 \fIfile_name\fB.dir\fR.
index 3711f8dd2f9f3dc6d83edb4f2e1e2433e049340e..fefde2869742bab7aa30fd233d751d7d4bab8558 100644 (file)
@@ -173,8 +173,8 @@ name. Originally implemented for testing, someone may find this
 useful someday.
 .IP \fBfail\fR
 A table that reliably fails all requests. The lookup table
-name provides the internal error result code. This table
-exists to simplify Postfix error tests.
+name is used for logging. This table exists to simplify
+Postfix error tests.
 .IP \fBhash\fR
 An indexed file type based on hashing.
 This is available on systems with support for Berkeley DB
index d79ac3510afdfe179d41eb998dfa690e7ebf4bf4..cf6ae52402af935dd441f5585ca1a6710a65fdeb 100644 (file)
@@ -189,6 +189,10 @@ This is available on systems with support for \fBdbm\fR databases.
 .IP \fBhash\fR
 The output file is a hashed file, named \fIfile_name\fB.db\fR.
 This is available on systems with support for \fBdb\fR databases.
+.IP \fBfail\fR
+A table that reliably fails all requests. The lookup table
+name is used for logging only. This table exists to simplify
+Postfix error tests.
 .IP \fBsdbm\fR
 The output consists of two files, named \fIfile_name\fB.pag\fR and
 \fIfile_name\fB.dir\fR.
index ca1627c74eab984f6d2ced6ce9955c0714e57c10..284f0278689404f349b66bef67861cf991e4b26a 100644 (file)
@@ -295,8 +295,8 @@ variable name. The lookup table name in "environ:table" is ignored.
 <dt> <b>fail</b> (read-write) </dt>
 
 <dd> A table that reliably fails all requests. The lookup table
-name provides the internal error result code. This table exists to
-simplify Postfix error tests. </dd>
+name is used for logging only. This table exists to simplify Postfix
+error tests. </dd>
 
 <dt> <b>hash</b> </dt>
 
index 7e28474b962f78ab03d2b721f7c70d5edfb28a3b..0dbbc1be5bd7bb6403af1b408ba80ec9c721f694 100644 (file)
@@ -528,7 +528,6 @@ cleanup.o: ../../include/mail_stream.h
 cleanup.o: ../../include/mail_version.h
 cleanup.o: ../../include/maps.h
 cleanup.o: ../../include/match_list.h
-cleanup.o: ../../include/match_ops.h
 cleanup.o: ../../include/milter.h
 cleanup.o: ../../include/mime_state.h
 cleanup.o: ../../include/msg.h
@@ -565,7 +564,6 @@ cleanup_addr.o: ../../include/mail_proto.h
 cleanup_addr.o: ../../include/mail_stream.h
 cleanup_addr.o: ../../include/maps.h
 cleanup_addr.o: ../../include/match_list.h
-cleanup_addr.o: ../../include/match_ops.h
 cleanup_addr.o: ../../include/milter.h
 cleanup_addr.o: ../../include/mime_state.h
 cleanup_addr.o: ../../include/msg.h
@@ -604,7 +602,6 @@ cleanup_api.o: ../../include/mail_queue.h
 cleanup_api.o: ../../include/mail_stream.h
 cleanup_api.o: ../../include/maps.h
 cleanup_api.o: ../../include/match_list.h
-cleanup_api.o: ../../include/match_ops.h
 cleanup_api.o: ../../include/milter.h
 cleanup_api.o: ../../include/mime_state.h
 cleanup_api.o: ../../include/msg.h
@@ -635,7 +632,6 @@ cleanup_body_edit.o: ../../include/mail_conf.h
 cleanup_body_edit.o: ../../include/mail_stream.h
 cleanup_body_edit.o: ../../include/maps.h
 cleanup_body_edit.o: ../../include/match_list.h
-cleanup_body_edit.o: ../../include/match_ops.h
 cleanup_body_edit.o: ../../include/milter.h
 cleanup_body_edit.o: ../../include/mime_state.h
 cleanup_body_edit.o: ../../include/msg.h
@@ -674,7 +670,6 @@ cleanup_bounce.o: ../../include/mail_queue.h
 cleanup_bounce.o: ../../include/mail_stream.h
 cleanup_bounce.o: ../../include/maps.h
 cleanup_bounce.o: ../../include/match_list.h
-cleanup_bounce.o: ../../include/match_ops.h
 cleanup_bounce.o: ../../include/milter.h
 cleanup_bounce.o: ../../include/mime_state.h
 cleanup_bounce.o: ../../include/msg.h
@@ -711,7 +706,6 @@ cleanup_envelope.o: ../../include/mail_proto.h
 cleanup_envelope.o: ../../include/mail_stream.h
 cleanup_envelope.o: ../../include/maps.h
 cleanup_envelope.o: ../../include/match_list.h
-cleanup_envelope.o: ../../include/match_ops.h
 cleanup_envelope.o: ../../include/milter.h
 cleanup_envelope.o: ../../include/mime_state.h
 cleanup_envelope.o: ../../include/msg.h
@@ -749,7 +743,6 @@ cleanup_extracted.o: ../../include/mail_proto.h
 cleanup_extracted.o: ../../include/mail_stream.h
 cleanup_extracted.o: ../../include/maps.h
 cleanup_extracted.o: ../../include/match_list.h
-cleanup_extracted.o: ../../include/match_ops.h
 cleanup_extracted.o: ../../include/milter.h
 cleanup_extracted.o: ../../include/mime_state.h
 cleanup_extracted.o: ../../include/msg.h
@@ -782,7 +775,6 @@ cleanup_final.o: ../../include/mail_conf.h
 cleanup_final.o: ../../include/mail_stream.h
 cleanup_final.o: ../../include/maps.h
 cleanup_final.o: ../../include/match_list.h
-cleanup_final.o: ../../include/match_ops.h
 cleanup_final.o: ../../include/milter.h
 cleanup_final.o: ../../include/mime_state.h
 cleanup_final.o: ../../include/msg.h
@@ -817,7 +809,6 @@ cleanup_init.o: ../../include/mail_stream.h
 cleanup_init.o: ../../include/mail_version.h
 cleanup_init.o: ../../include/maps.h
 cleanup_init.o: ../../include/match_list.h
-cleanup_init.o: ../../include/match_ops.h
 cleanup_init.o: ../../include/milter.h
 cleanup_init.o: ../../include/mime_state.h
 cleanup_init.o: ../../include/msg.h
@@ -848,7 +839,6 @@ cleanup_map11.o: ../../include/mail_conf.h
 cleanup_map11.o: ../../include/mail_stream.h
 cleanup_map11.o: ../../include/maps.h
 cleanup_map11.o: ../../include/match_list.h
-cleanup_map11.o: ../../include/match_ops.h
 cleanup_map11.o: ../../include/milter.h
 cleanup_map11.o: ../../include/mime_state.h
 cleanup_map11.o: ../../include/msg.h
@@ -880,7 +870,6 @@ cleanup_map1n.o: ../../include/mail_params.h
 cleanup_map1n.o: ../../include/mail_stream.h
 cleanup_map1n.o: ../../include/maps.h
 cleanup_map1n.o: ../../include/match_list.h
-cleanup_map1n.o: ../../include/match_ops.h
 cleanup_map1n.o: ../../include/milter.h
 cleanup_map1n.o: ../../include/mime_state.h
 cleanup_map1n.o: ../../include/msg.h
@@ -911,7 +900,6 @@ cleanup_masquerade.o: ../../include/mail_params.h
 cleanup_masquerade.o: ../../include/mail_stream.h
 cleanup_masquerade.o: ../../include/maps.h
 cleanup_masquerade.o: ../../include/match_list.h
-cleanup_masquerade.o: ../../include/match_ops.h
 cleanup_masquerade.o: ../../include/milter.h
 cleanup_masquerade.o: ../../include/mime_state.h
 cleanup_masquerade.o: ../../include/msg.h
@@ -952,7 +940,6 @@ cleanup_message.o: ../../include/mail_proto.h
 cleanup_message.o: ../../include/mail_stream.h
 cleanup_message.o: ../../include/maps.h
 cleanup_message.o: ../../include/match_list.h
-cleanup_message.o: ../../include/match_ops.h
 cleanup_message.o: ../../include/milter.h
 cleanup_message.o: ../../include/mime_state.h
 cleanup_message.o: ../../include/msg.h
@@ -992,7 +979,6 @@ cleanup_milter.o: ../../include/mail_proto.h
 cleanup_milter.o: ../../include/mail_stream.h
 cleanup_milter.o: ../../include/maps.h
 cleanup_milter.o: ../../include/match_list.h
-cleanup_milter.o: ../../include/match_ops.h
 cleanup_milter.o: ../../include/milter.h
 cleanup_milter.o: ../../include/mime_state.h
 cleanup_milter.o: ../../include/msg.h
@@ -1029,7 +1015,6 @@ cleanup_out.o: ../../include/mail_params.h
 cleanup_out.o: ../../include/mail_stream.h
 cleanup_out.o: ../../include/maps.h
 cleanup_out.o: ../../include/match_list.h
-cleanup_out.o: ../../include/match_ops.h
 cleanup_out.o: ../../include/milter.h
 cleanup_out.o: ../../include/mime_state.h
 cleanup_out.o: ../../include/msg.h
@@ -1069,7 +1054,6 @@ cleanup_out_recipient.o: ../../include/mail_queue.h
 cleanup_out_recipient.o: ../../include/mail_stream.h
 cleanup_out_recipient.o: ../../include/maps.h
 cleanup_out_recipient.o: ../../include/match_list.h
-cleanup_out_recipient.o: ../../include/match_ops.h
 cleanup_out_recipient.o: ../../include/milter.h
 cleanup_out_recipient.o: ../../include/mime_state.h
 cleanup_out_recipient.o: ../../include/msg.h
@@ -1101,7 +1085,6 @@ cleanup_region.o: ../../include/mail_conf.h
 cleanup_region.o: ../../include/mail_stream.h
 cleanup_region.o: ../../include/maps.h
 cleanup_region.o: ../../include/match_list.h
-cleanup_region.o: ../../include/match_ops.h
 cleanup_region.o: ../../include/milter.h
 cleanup_region.o: ../../include/mime_state.h
 cleanup_region.o: ../../include/msg.h
@@ -1131,7 +1114,6 @@ cleanup_rewrite.o: ../../include/mail_proto.h
 cleanup_rewrite.o: ../../include/mail_stream.h
 cleanup_rewrite.o: ../../include/maps.h
 cleanup_rewrite.o: ../../include/match_list.h
-cleanup_rewrite.o: ../../include/match_ops.h
 cleanup_rewrite.o: ../../include/milter.h
 cleanup_rewrite.o: ../../include/mime_state.h
 cleanup_rewrite.o: ../../include/msg.h
@@ -1165,7 +1147,6 @@ cleanup_state.o: ../../include/mail_proto.h
 cleanup_state.o: ../../include/mail_stream.h
 cleanup_state.o: ../../include/maps.h
 cleanup_state.o: ../../include/match_list.h
-cleanup_state.o: ../../include/match_ops.h
 cleanup_state.o: ../../include/milter.h
 cleanup_state.o: ../../include/mime_state.h
 cleanup_state.o: ../../include/mymalloc.h
index 7673667a8aa0c42ec46f5f62716d3c9790779858..626b9ff3acaa15df7f30100e32813d11e9f65a4d 100644 (file)
@@ -119,7 +119,7 @@ int     cleanup_map11_external(CLEANUP_STATE *state, VSTRING *addr,
            argv_free(new_addr);
            if (expand_to_self)
                return (did_rewrite);
-       } else if (dict_errno != 0) {
+       } else if (maps->error != 0) {
            msg_warn("%s: %s map lookup problem for %s",
                     state->queue_id, maps->title, STR(addr));
            state->errs |= CLEANUP_STAT_WRITE;
index b806a6017a99928a819a694dcf770840db8cd10c..f7088a06b56edf7fa87746879d71d8bf747efbe9 100644 (file)
@@ -155,7 +155,7 @@ ARGV   *cleanup_map1n_internal(CLEANUP_STATE *state, const char *addr,
                }
                myfree(saved_lhs);
                argv_free(lookup);
-           } else if (dict_errno != 0) {
+           } else if (maps->error != 0) {
                msg_warn("%s: %s map lookup problem for %s -- "
                         "deferring delivery",
                         state->queue_id, maps->title, addr);
index 8e35af84059cd2849f031f2d7cc030fa2aebc7d1..a529c62cef700d2c10ee5ae09b4931a9a048ef83 100644 (file)
       747 original_recipient: alias@hades.porcupine.org
       774 canceled_recipient: root@porcupine.org
       794 pointer_record:            1258
-     1258 named_attribute: notify_flags=1
-     1274 original_recipient: xxxx
-     1280 recipient: xxxx
-     1286 pointer_record:            1303
-     1303 named_attribute: notify_flags=1
-     1319 original_recipient: yyyy
-     1325 canceled_recipient: yyyy
-     1331 pointer_record:             811
+     1258 original_recipient: xxxx
+     1264 recipient: xxxx
+     1270 pointer_record:            1287
+     1287 original_recipient: yyyy
+     1293 canceled_recipient: yyyy
+     1299 pointer_record:             811
       811 *** MESSAGE CONTENTS test-queue-file.tmp ***
       813 regular_text: Received: from hades.porcupine.org (hades.porcupine.org [168.100.189.10])
       888 regular_text:        by hades.porcupine.org (Postfix) with SMTP id 38132290405;
       949 regular_text:        Sat, 20 Jan 2007 19:52:41 -0500 (EST)
-      989 pointer_record:            1348
-     1348 pointer_record:            1399
-     1399 pointer_record:            1365
-     1365 pointer_record:            1492
-     1492 regular_text: X: X-replaced-header replacement header text
-     1538 pointer_record:            1433
-     1433 regular_text: X2: test header value 3
-     1458 regular_text: Y: 1234567
-     1470 padding:   0
-     1475 pointer_record:            1047
+      989 pointer_record:            1316
+     1316 pointer_record:            1367
+     1367 pointer_record:            1333
+     1333 pointer_record:            1460
+     1460 regular_text: X: X-replaced-header replacement header text
+     1506 pointer_record:            1401
+     1401 regular_text: X2: test header value 3
+     1426 regular_text: Y: 1234567
+     1438 padding:   0
+     1443 pointer_record:            1047
      1047 regular_text: Message-Id: <20070121005247.38132290405@hades.porcupine.org>
      1109 regular_text: Date: Sat, 20 Jan 2007 19:52:41 -0500 (EST)
      1154 regular_text: From: wietse@porcupine.org
index 58dc6f573ba3f144431882d9e579cff328d7f2ca..d5d0f2c04a01ba67f1de62087c45e0c27f191eff 100644 (file)
       516 original_recipient: you@porcupine.org
       535 recipient: you@porcupine.org
       554 pointer_record:             573
-      573 named_attribute: notify_flags=1
-      589 original_recipient: me@porcupine.org
-      607 canceled_recipient: me@porcupine.org
-      625 pointer_record:             642
-      642 named_attribute: notify_flags=1
-      658 original_recipient: em@porcupine.org
-      676 canceled_recipient: em@porcupine.org
-      694 pointer_record:             571
+      573 original_recipient: me@porcupine.org
+      591 canceled_recipient: me@porcupine.org
+      609 pointer_record:             626
+      626 original_recipient: em@porcupine.org
+      644 canceled_recipient: em@porcupine.org
+      662 pointer_record:             571
       571 *** MESSAGE FILE END test-queue-file12.tmp ***
index 8a1d610e84be6e3a9cbf933c9eb4a0c208c89f43..3ccf0282fed00384d6a847d31b92c6c72e1e7ce3 100644 (file)
       516 original_recipient: you@porcupine.org
       535 recipient: you@porcupine.org
       554 pointer_record:             573
-      573 named_attribute: notify_flags=1
-      589 original_recipient: me@porcupine.org
-      607 canceled_recipient: me@porcupine.org
-      625 pointer_record:             642
-      642 named_attribute: notify_flags=1
-      658 original_recipient: em@porcupine.org
-      676 canceled_recipient: em@porcupine.org
-      694 pointer_record:             571
+      573 original_recipient: me@porcupine.org
+      591 canceled_recipient: me@porcupine.org
+      609 pointer_record:             626
+      626 original_recipient: em@porcupine.org
+      644 canceled_recipient: em@porcupine.org
+      662 pointer_record:             571
       571 *** MESSAGE FILE END test-queue-file13a.tmp ***
index 84ae4efb45e815a30a82018e2cd97d744e928140..656b561949b3fdbabda372bf0d5881405538ba26 100644 (file)
@@ -6,42 +6,40 @@
       147 sender_fullname: Wietse Venema
       162 sender: me@porcupine.org
       180 pointer_record:             573
-      573 named_attribute: notify_flags=1
-      589 original_recipient: me@porcupine.org
-      607 canceled_recipient: me@porcupine.org
-      625 pointer_record:            1413
-     1413 named_attribute: notify_flags=1
-     1429 original_recipient: em@porcupine.org
-     1447 canceled_recipient: em@porcupine.org
-     1465 pointer_record:             197
+      573 original_recipient: me@porcupine.org
+      591 canceled_recipient: me@porcupine.org
+      609 pointer_record:            1397
+     1397 original_recipient: em@porcupine.org
+     1415 canceled_recipient: em@porcupine.org
+     1433 pointer_record:             197
       197 *** MESSAGE CONTENTS test-queue-file3.tmp ***
       199 regular_text: Received: by hades.porcupine.org (Postfix, from userid 1001)
       261 regular_text:        id B85F1290407; Sat, 20 Jan 2007 20:53:59 -0500 (EST)
-      317 pointer_record:             858
-      858 pointer_record:            1331
-     1331 pointer_record:            1372
-     1372 pointer_record:            1482
-     1482 pointer_record:            1739
-     1739 pointer_record:            1780
-     1780 regular_text: From: me@porcupine.org
-     1804 pointer_record:            1523
-     1523 pointer_record:            1821
-     1821 pointer_record:            1861
-     1861 regular_text: To: you@porcupine.org
-     1884 pointer_record:            1563
-     1563 pointer_record:            1901
-     1901 pointer_record:            1980
-     1980 regular_text: Message-Id: <20060725192735.5EC2D29013F@hades.porcupine.org>
-     2042 pointer_record:            1642
-     1642 pointer_record:            2059
-     2059 pointer_record:            2121
-     2121 regular_text: Date: Tue, 25 Jul 2006 15:27:19 -0400 (EDT)
-     2166 pointer_record:            1704
-     1704 pointer_record:            2183
-     2183 pointer_record:            2218
-     2218 regular_text: Subject: hey!
-     2233 padding: 0
-     2236 pointer_record:             489
+      317 pointer_record:             842
+      842 pointer_record:            1315
+     1315 pointer_record:            1356
+     1356 pointer_record:            1450
+     1450 pointer_record:            1707
+     1707 pointer_record:            1748
+     1748 regular_text: From: me@porcupine.org
+     1772 pointer_record:            1491
+     1491 pointer_record:            1789
+     1789 pointer_record:            1829
+     1829 regular_text: To: you@porcupine.org
+     1852 pointer_record:            1531
+     1531 pointer_record:            1869
+     1869 pointer_record:            1948
+     1948 regular_text: Message-Id: <20060725192735.5EC2D29013F@hades.porcupine.org>
+     2010 pointer_record:            1610
+     1610 pointer_record:            2027
+     2027 pointer_record:            2089
+     2089 regular_text: Date: Tue, 25 Jul 2006 15:27:19 -0400 (EDT)
+     2134 pointer_record:            1672
+     1672 pointer_record:            2151
+     2151 pointer_record:            2186
+     2186 regular_text: Subject: hey!
+     2201 padding: 0
+     2204 pointer_record:             489
       489 pointer_record:               0
       506 regular_text: 
       508 regular_text: text
index 5c8993eee21f23f900b9985975b1ee675356031b..4c3be60a8b11188db432b2b7d9fce0e12bb6953d 100644 (file)
       747 original_recipient: alias@hades.porcupine.org
       774 recipient: root@porcupine.org
       794 pointer_record:            1258
-     1258 named_attribute: notify_flags=1
-     1274 original_recipient: 01
-     1278 canceled_recipient: 01
-     1282 pointer_record:            1299
-     1299 named_attribute: notify_flags=1
-     1315 original_recipient: 02
-     1319 canceled_recipient: 02
-     1323 pointer_record:            1340
-     1340 named_attribute: notify_flags=1
-     1356 original_recipient: 03
-     1360 canceled_recipient: 03
-     1364 pointer_record:             811
+     1258 original_recipient: 01
+     1262 canceled_recipient: 01
+     1266 pointer_record:            1283
+     1283 original_recipient: 02
+     1287 canceled_recipient: 02
+     1291 pointer_record:            1308
+     1308 original_recipient: 03
+     1312 canceled_recipient: 03
+     1316 pointer_record:             811
       811 *** MESSAGE CONTENTS test-queue-file4.tmp ***
       813 regular_text: Received: from hades.porcupine.org (hades.porcupine.org [168.100.189.10])
       888 regular_text:        by hades.porcupine.org (Postfix) with SMTP id 38132290405;
index 7578940f561165e2320c9cf380c8d0a57d43210a..ea0b6df796f0712581f559c071aca11faa86ebd6 100644 (file)
@@ -75,7 +75,6 @@ flush.o: ../../include/mail_server.h
 flush.o: ../../include/mail_version.h
 flush.o: ../../include/maps.h
 flush.o: ../../include/match_list.h
-flush.o: ../../include/match_ops.h
 flush.o: ../../include/match_parent_style.h
 flush.o: ../../include/msg.h
 flush.o: ../../include/myflock.h
index e496ca9fc658b4148e4eabc33d3910c314793243..0a5d596ef96af44f1533639cfa3f36695dfb4a47 100644 (file)
@@ -31,7 +31,8 @@ SRCS  = abounce.c anvil_clnt.c been_here.c bounce.c bounce_log.c \
        fold_addr.c header_body_checks.c mkmap_proxy.c data_redirect.c \
        match_service.c mail_conf_nint.c addr_match_list.c mail_conf_nbool.c \
        smtp_reply_footer.c safe_ultostr.c verify_sender_addr.c \
-       dict_memcache.c mail_version.c memcache_proto.c server_acl.c
+       dict_memcache.c mail_version.c memcache_proto.c server_acl.c \
+       mkmap_fail.c
 OBJS   = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
        canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \
        clnt_stream.o conv_time.o db_common.o debug_peer.o debug_process.o \
@@ -64,7 +65,8 @@ OBJS  = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
        fold_addr.o header_body_checks.o mkmap_proxy.o data_redirect.o \
        match_service.o mail_conf_nint.o addr_match_list.o mail_conf_nbool.o \
        smtp_reply_footer.o safe_ultostr.o verify_sender_addr.o \
-       dict_memcache.o mail_version.o memcache_proto.o server_acl.o
+       dict_memcache.o mail_version.o memcache_proto.o server_acl.o \
+       mkmap_fail.o
 HDRS   = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
        canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \
        conv_time.h db_common.h debug_peer.h debug_process.h defer.h \
@@ -596,13 +598,8 @@ abounce.o: mail_proto.h
 abounce.o: msg_stats.h
 abounce.o: recipient_list.h
 addr_match_list.o: ../../include/argv.h
-addr_match_list.o: ../../include/dict.h
 addr_match_list.o: ../../include/match_list.h
-addr_match_list.o: ../../include/match_ops.h
 addr_match_list.o: ../../include/sys_defs.h
-addr_match_list.o: ../../include/vbuf.h
-addr_match_list.o: ../../include/vstream.h
-addr_match_list.o: ../../include/vstring.h
 addr_match_list.o: addr_match_list.c
 addr_match_list.o: addr_match_list.h
 anvil_clnt.o: ../../include/attr.h
@@ -742,7 +739,6 @@ data_redirect.o: mail_params.h
 db_common.o: ../../include/argv.h
 db_common.o: ../../include/dict.h
 db_common.o: ../../include/match_list.h
-db_common.o: ../../include/match_ops.h
 db_common.o: ../../include/msg.h
 db_common.o: ../../include/mymalloc.h
 db_common.o: ../../include/sys_defs.h
@@ -754,14 +750,9 @@ db_common.o: db_common.c
 db_common.o: db_common.h
 db_common.o: string_list.h
 debug_peer.o: ../../include/argv.h
-debug_peer.o: ../../include/dict.h
 debug_peer.o: ../../include/match_list.h
-debug_peer.o: ../../include/match_ops.h
 debug_peer.o: ../../include/msg.h
 debug_peer.o: ../../include/sys_defs.h
-debug_peer.o: ../../include/vbuf.h
-debug_peer.o: ../../include/vstream.h
-debug_peer.o: ../../include/vstring.h
 debug_peer.o: debug_peer.c
 debug_peer.o: debug_peer.h
 debug_peer.o: mail_params.h
@@ -878,7 +869,6 @@ dict_ldap.o: ../../include/argv.h
 dict_ldap.o: ../../include/binhash.h
 dict_ldap.o: ../../include/dict.h
 dict_ldap.o: ../../include/match_list.h
-dict_ldap.o: ../../include/match_ops.h
 dict_ldap.o: ../../include/msg.h
 dict_ldap.o: ../../include/mymalloc.h
 dict_ldap.o: ../../include/name_code.h
@@ -897,7 +887,6 @@ dict_memcache.o: ../../include/argv.h
 dict_memcache.o: ../../include/auto_clnt.h
 dict_memcache.o: ../../include/dict.h
 dict_memcache.o: ../../include/match_list.h
-dict_memcache.o: ../../include/match_ops.h
 dict_memcache.o: ../../include/msg.h
 dict_memcache.o: ../../include/mymalloc.h
 dict_memcache.o: ../../include/stringops.h
@@ -911,46 +900,10 @@ dict_memcache.o: dict_memcache.c
 dict_memcache.o: dict_memcache.h
 dict_memcache.o: memcache_proto.h
 dict_memcache.o: string_list.h
-dict_mysql.o: ../../include/argv.h
-dict_mysql.o: ../../include/dict.h
-dict_mysql.o: ../../include/events.h
-dict_mysql.o: ../../include/find_inet.h
-dict_mysql.o: ../../include/match_list.h
-dict_mysql.o: ../../include/match_ops.h
-dict_mysql.o: ../../include/msg.h
-dict_mysql.o: ../../include/mymalloc.h
-dict_mysql.o: ../../include/myrand.h
-dict_mysql.o: ../../include/split_at.h
-dict_mysql.o: ../../include/stringops.h
 dict_mysql.o: ../../include/sys_defs.h
-dict_mysql.o: ../../include/vbuf.h
-dict_mysql.o: ../../include/vstream.h
-dict_mysql.o: ../../include/vstring.h
-dict_mysql.o: cfg_parser.h
-dict_mysql.o: db_common.h
 dict_mysql.o: dict_mysql.c
-dict_mysql.o: dict_mysql.h
-dict_mysql.o: string_list.h
-dict_pgsql.o: ../../include/argv.h
-dict_pgsql.o: ../../include/dict.h
-dict_pgsql.o: ../../include/events.h
-dict_pgsql.o: ../../include/find_inet.h
-dict_pgsql.o: ../../include/match_list.h
-dict_pgsql.o: ../../include/match_ops.h
-dict_pgsql.o: ../../include/msg.h
-dict_pgsql.o: ../../include/mymalloc.h
-dict_pgsql.o: ../../include/myrand.h
-dict_pgsql.o: ../../include/split_at.h
-dict_pgsql.o: ../../include/stringops.h
 dict_pgsql.o: ../../include/sys_defs.h
-dict_pgsql.o: ../../include/vbuf.h
-dict_pgsql.o: ../../include/vstream.h
-dict_pgsql.o: ../../include/vstring.h
-dict_pgsql.o: cfg_parser.h
-dict_pgsql.o: db_common.h
 dict_pgsql.o: dict_pgsql.c
-dict_pgsql.o: dict_pgsql.h
-dict_pgsql.o: string_list.h
 dict_proxy.o: ../../include/argv.h
 dict_proxy.o: ../../include/attr.h
 dict_proxy.o: ../../include/dict.h
@@ -970,7 +923,6 @@ dict_proxy.o: mail_proto.h
 dict_sqlite.o: ../../include/argv.h
 dict_sqlite.o: ../../include/dict.h
 dict_sqlite.o: ../../include/match_list.h
-dict_sqlite.o: ../../include/match_ops.h
 dict_sqlite.o: ../../include/msg.h
 dict_sqlite.o: ../../include/mymalloc.h
 dict_sqlite.o: ../../include/stringops.h
@@ -984,13 +936,8 @@ dict_sqlite.o: dict_sqlite.c
 dict_sqlite.o: dict_sqlite.h
 dict_sqlite.o: string_list.h
 domain_list.o: ../../include/argv.h
-domain_list.o: ../../include/dict.h
 domain_list.o: ../../include/match_list.h
-domain_list.o: ../../include/match_ops.h
 domain_list.o: ../../include/sys_defs.h
-domain_list.o: ../../include/vbuf.h
-domain_list.o: ../../include/vstream.h
-domain_list.o: ../../include/vstring.h
 domain_list.o: domain_list.c
 domain_list.o: domain_list.h
 dot_lockfile.o: ../../include/iostuff.h
@@ -1083,15 +1030,12 @@ file_id.o: mail_queue.h
 file_id.o: safe_ultostr.h
 flush_clnt.o: ../../include/argv.h
 flush_clnt.o: ../../include/attr.h
-flush_clnt.o: ../../include/dict.h
 flush_clnt.o: ../../include/iostuff.h
 flush_clnt.o: ../../include/match_list.h
-flush_clnt.o: ../../include/match_ops.h
 flush_clnt.o: ../../include/msg.h
 flush_clnt.o: ../../include/sys_defs.h
 flush_clnt.o: ../../include/vbuf.h
 flush_clnt.o: ../../include/vstream.h
-flush_clnt.o: ../../include/vstring.h
 flush_clnt.o: domain_list.h
 flush_clnt.o: flush_clnt.c
 flush_clnt.o: flush_clnt.h
@@ -1545,13 +1489,8 @@ mark_corrupt.o: mark_corrupt.h
 mark_corrupt.o: msg_stats.h
 mark_corrupt.o: recipient_list.h
 match_parent_style.o: ../../include/argv.h
-match_parent_style.o: ../../include/dict.h
 match_parent_style.o: ../../include/match_list.h
-match_parent_style.o: ../../include/match_ops.h
 match_parent_style.o: ../../include/sys_defs.h
-match_parent_style.o: ../../include/vbuf.h
-match_parent_style.o: ../../include/vstream.h
-match_parent_style.o: ../../include/vstring.h
 match_parent_style.o: mail_params.h
 match_parent_style.o: match_parent_style.c
 match_parent_style.o: match_parent_style.h
@@ -1611,7 +1550,15 @@ mime_state.o: mail_params.h
 mime_state.o: mime_state.c
 mime_state.o: mime_state.h
 mime_state.o: rec_type.h
+mkmap_cdb.o: ../../include/argv.h
+mkmap_cdb.o: ../../include/dict.h
+mkmap_cdb.o: ../../include/dict_cdb.h
+mkmap_cdb.o: ../../include/mymalloc.h
 mkmap_cdb.o: ../../include/sys_defs.h
+mkmap_cdb.o: ../../include/vbuf.h
+mkmap_cdb.o: ../../include/vstream.h
+mkmap_cdb.o: ../../include/vstring.h
+mkmap_cdb.o: mkmap.h
 mkmap_cdb.o: mkmap_cdb.c
 mkmap_db.o: ../../include/argv.h
 mkmap_db.o: ../../include/dict.h
@@ -1640,11 +1587,22 @@ mkmap_dbm.o: ../../include/vstream.h
 mkmap_dbm.o: ../../include/vstring.h
 mkmap_dbm.o: mkmap.h
 mkmap_dbm.o: mkmap_dbm.c
+mkmap_fail.o: ../../include/argv.h
+mkmap_fail.o: ../../include/dict.h
+mkmap_fail.o: ../../include/dict_fail.h
+mkmap_fail.o: ../../include/mymalloc.h
+mkmap_fail.o: ../../include/sys_defs.h
+mkmap_fail.o: ../../include/vbuf.h
+mkmap_fail.o: ../../include/vstream.h
+mkmap_fail.o: ../../include/vstring.h
+mkmap_fail.o: mkmap.h
+mkmap_fail.o: mkmap_fail.c
 mkmap_open.o: ../../include/argv.h
 mkmap_open.o: ../../include/dict.h
 mkmap_open.o: ../../include/dict_cdb.h
 mkmap_open.o: ../../include/dict_db.h
 mkmap_open.o: ../../include/dict_dbm.h
+mkmap_open.o: ../../include/dict_fail.h
 mkmap_open.o: ../../include/dict_sdbm.h
 mkmap_open.o: ../../include/msg.h
 mkmap_open.o: ../../include/mymalloc.h
@@ -1721,13 +1679,8 @@ mypwd.o: ../../include/sys_defs.h
 mypwd.o: mypwd.c
 mypwd.o: mypwd.h
 namadr_list.o: ../../include/argv.h
-namadr_list.o: ../../include/dict.h
 namadr_list.o: ../../include/match_list.h
-namadr_list.o: ../../include/match_ops.h
 namadr_list.o: ../../include/sys_defs.h
-namadr_list.o: ../../include/vbuf.h
-namadr_list.o: ../../include/vstream.h
-namadr_list.o: ../../include/vstring.h
 namadr_list.o: namadr_list.c
 namadr_list.o: namadr_list.h
 off_cvt.o: ../../include/msg.h
@@ -1905,7 +1858,6 @@ resolve_local.o: ../../include/argv.h
 resolve_local.o: ../../include/dict.h
 resolve_local.o: ../../include/inet_addr_list.h
 resolve_local.o: ../../include/match_list.h
-resolve_local.o: ../../include/match_ops.h
 resolve_local.o: ../../include/msg.h
 resolve_local.o: ../../include/myaddrinfo.h
 resolve_local.o: ../../include/mymalloc.h
@@ -2009,7 +1961,6 @@ sent.o: verify.h
 server_acl.o: ../../include/argv.h
 server_acl.o: ../../include/dict.h
 server_acl.o: ../../include/match_list.h
-server_acl.o: ../../include/match_ops.h
 server_acl.o: ../../include/msg.h
 server_acl.o: ../../include/mymalloc.h
 server_acl.o: ../../include/stringops.h
@@ -2055,13 +2006,8 @@ stream2rec.o: rec_type.h
 stream2rec.o: record.h
 stream2rec.o: stream2rec.c
 string_list.o: ../../include/argv.h
-string_list.o: ../../include/dict.h
 string_list.o: ../../include/match_list.h
-string_list.o: ../../include/match_ops.h
 string_list.o: ../../include/sys_defs.h
-string_list.o: ../../include/vbuf.h
-string_list.o: ../../include/vstream.h
-string_list.o: ../../include/vstring.h
 string_list.o: string_list.c
 string_list.o: string_list.h
 strip_addr.o: ../../include/mymalloc.h
@@ -2156,7 +2102,6 @@ user_acl.o: ../../include/argv.h
 user_acl.o: ../../include/dict.h
 user_acl.o: ../../include/dict_static.h
 user_acl.o: ../../include/match_list.h
-user_acl.o: ../../include/match_ops.h
 user_acl.o: ../../include/sys_defs.h
 user_acl.o: ../../include/vbuf.h
 user_acl.o: ../../include/vstream.h
index 86cbe9c559d1c38131e80c133b4b91bf7663ddfa..946cf4ae3b6ac6a9a835c693240427b743100f75 100644 (file)
@@ -37,8 +37,9 @@
 /*     addr_match_list_init() performs initializations. The first
 /*     argument is the bit-wise OR of zero or more of the following:
 /* .IP MATCH_FLAG_RETURN
-/*     Request that addr_match_list_match() returns zero with
-/*     dict_errno != 0, instead of raising a fatal error.
+/*     Request that addr_match_list_match() logs a warning and
+/*     returns zero with list->error set to a non-zero dictionary
+/*     error code, instead of raising a fatal error.
 /* .PP
 /*     Specify MATCH_FLAG_NONE to request none of the above.
 /*     The second argument is a list of patterns, or the absolute
@@ -120,12 +121,12 @@ int     main(int argc, char **argv)
        while (vstring_get_nonl(buf, VSTREAM_IN) != VSTREAM_EOF)
            vstream_printf("%s: %s\n", vstring_str(buf),
                           addr_match_list_match(list, vstring_str(buf)) ?
-                          "YES" : dict_errno == 0 ? "NO" : "ERROR");
+                          "YES" : list->error == 0 ? "NO" : "ERROR");
        vstring_free(buf);
     } else {
        vstream_printf("%s: %s\n", addr,
                       addr_match_list_match(list, addr) > 0 ?
-                      "YES" : dict_errno == 0 ? "NO" : "ERROR");
+                      "YES" : list->error == 0 ? "NO" : "ERROR");
     }
     vstream_fflush(VSTREAM_OUT);
     addr_match_list_free(list);
index 4dbeedb937871a60c3dc632f69dac16b7183d948..6b3edbdf8a06a66529a67417685b343f7fffca38 100644 (file)
 /*     If \fIkey\fR is a fully qualified address, the domain part of the
 /*     address.  Otherwise the query against the database is suppressed and
 /*     the lookup returns no results.
-/*
 /* .PP
-/*     \fIdb_common_check_domain\fR checks domain list so that query optimization
-/*     can be performed
+/*     \fIdb_common_check_domain\fR() checks the domain list so
+/*     that query optimization can be performed. The result is >0
+/*     (match found), 0 (no match), or <0 (dictionary error code).
 /*
 /* .PP
 /*     \fIdb_common_sql_build_query\fR builds the "default"(backwards compatible)
@@ -256,7 +256,7 @@ void    db_common_parse_domain(CFG_PARSER *parser, void *ctxPtr)
 
     domainlist = cfg_get_str(parser, "domain", "", 0, 0);
     if (*domainlist) {
-       ctx->domain = string_list_init(MATCH_FLAG_NONE, domainlist);
+       ctx->domain = string_list_init(MATCH_FLAG_RETURN, domainlist);
        if (ctx->domain == 0)
 
            /*
@@ -528,7 +528,7 @@ int     db_common_check_domain(void *ctxPtr, const char *addr)
        if (domain == NULL || domain == addr + 1)
            return (0);
        if (match_list_match(ctx->domain, domain) == 0)
-           return (0);
+           return (ctx->domain->error);
     }
     return (1);
 }
index 0a5bb53b95aa61bbd006df1fcd4a4f3d718965db..6398dcc890df419990cfaf5b80b623aafc46f667 100644 (file)
 /* .IP recursion_limit
 /*     Maximum recursion depth when expanding DN or URL references.
 /*     Queries which exceed the recursion limit fail with
-/*     dict_errno = DICT_ERR_RETRY.
+/*     dict->error = DICT_ERR_RETRY.
 /* .IP expansion_limit
 /*     Limit (if any) on the total number of lookup result values. Lookups which
-/*     exceed the limit fail with dict_errno=DICT_ERR_RETRY. Note that
+/*     exceed the limit fail with dict->error=DICT_ERR_RETRY. Note that
 /*     each value of a multivalued result attribute counts as one result.
 /* .IP size_limit
 /*     Limit on the number of entries returned by individual LDAP queries.
-/*     Queries which exceed the limit fail with dict_errno=DICT_ERR_RETRY.
+/*     Queries which exceed the limit fail with dict->error=DICT_ERR_RETRY.
 /*     This is an *entry* count, for any single query performed during the
 /*     possibly recursive lookup.
 /* .IP chase_referrals
@@ -317,7 +317,7 @@ typedef struct {
 #define DICT_LDAP_UNBIND_RETURN(__ld, __err, __ret) do { \
        dict_ldap_unbind(__ld); \
        (__ld) = 0; \
-       dict_errno = (__err); \
+       dict_ldap->dict.error = (__err); \
        return ((__ret)); \
     } while (0)
 
@@ -728,7 +728,7 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
        msg_warn("%s: Unable to set LDAP debug level.", myname);
 #endif
 
-    dict_errno = 0;
+    dict_ldap->dict.error = 0;
 
     if (msg_verbose)
        msg_info("%s: Connecting to server %s", myname,
@@ -744,7 +744,7 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
     if (dict_ldap->ld == NULL) {
        msg_warn("%s: Unable to init LDAP server %s",
                 myname, dict_ldap->server_host);
-       dict_errno = DICT_ERR_RETRY;
+       dict_ldap->dict.error = DICT_ERR_RETRY;
        return (-1);
     }
     mytimeval.tv_sec = dict_ldap->timeout;
@@ -758,7 +758,7 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
     if ((saved_alarm = signal(SIGALRM, dict_ldap_timeout)) == SIG_ERR) {
        msg_warn("%s: Error setting signal handler for open timeout: %m",
                 myname);
-       dict_errno = DICT_ERR_RETRY;
+       dict_ldap->dict.error = DICT_ERR_RETRY;
        return (-1);
     }
     alarm(dict_ldap->timeout);
@@ -772,13 +772,13 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
     if (signal(SIGALRM, saved_alarm) == SIG_ERR) {
        msg_warn("%s: Error resetting signal handler after open: %m",
                 myname);
-       dict_errno = DICT_ERR_RETRY;
+       dict_ldap->dict.error = DICT_ERR_RETRY;
        return (-1);
     }
     if (dict_ldap->ld == NULL) {
        msg_warn("%s: Unable to connect to LDAP server %s",
                 myname, dict_ldap->server_host);
-       dict_errno = DICT_ERR_RETRY;
+       dict_ldap->dict.error = DICT_ERR_RETRY;
        return (-1);
     }
 #endif
@@ -861,13 +861,13 @@ static int dict_ldap_connect(DICT_LDAP *dict_ldap)
        if (signal(SIGALRM, saved_alarm) == SIG_ERR) {
            msg_warn("%s: Error resetting signal handler after STARTTLS: %m",
                     myname);
-           dict_errno = DICT_ERR_RETRY;
+           dict_ldap->dict.error = DICT_ERR_RETRY;
            return (-1);
        }
        if (rc != LDAP_SUCCESS) {
            msg_error("%s: Unable to set STARTTLS: %d: %s", myname,
                      rc, ldap_err2string(rc));
-           dict_errno = DICT_ERR_RETRY;
+           dict_ldap->dict.error = DICT_ERR_RETRY;
            return (-1);
        }
     }
@@ -1104,13 +1104,13 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage *res,
         * LDAP should not, but may produce more than the requested maximum
         * number of entries.
         */
-       if (dict_errno == 0
+       if (dict_ldap->dict.error == 0
            && dict_ldap->size_limit
            && ++entries > dict_ldap->size_limit) {
            msg_warn("%s[%d]: %s: Query size limit (%ld) exceeded",
                     myname, recursion, dict_ldap->parser->name,
                     dict_ldap->size_limit);
-           dict_errno = DICT_ERR_RETRY;
+           dict_ldap->dict.error = DICT_ERR_RETRY;
        }
 
        /*
@@ -1169,7 +1169,7 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage *res,
             * leaks, but it will likely be more fragile and not worth the
             * extra code.
             */
-           if (dict_errno != 0 || valcount == 0) {
+           if (dict_ldap->dict.error != 0 || valcount == 0) {
                ldap_value_free_len(vals);
                continue;
            }
@@ -1214,11 +1214,11 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage *res,
                            msg_warn("%s[%d]: %s: Expansion limit exceeded "
                                     "for key: '%s'", myname, recursion,
                                     dict_ldap->parser->name, name);
-                           dict_errno = DICT_ERR_RETRY;
+                           dict_ldap->dict.error = DICT_ERR_RETRY;
                            break;
                        }
                    }
-                   if (dict_errno != 0)
+                   if (dict_ldap->dict.error != 0)
                        continue;
                    if (msg_verbose)
                        msg_info("%s[%d]: search returned %d value(s) for"
@@ -1255,7 +1255,7 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage *res,
                            msg_warn("%s[%d]: malformed URL %s: %s(%d)",
                                     myname, recursion, vals[i]->bv_val,
                                     ldap_err2string(rc), rc);
-                           dict_errno = DICT_ERR_RETRY;
+                           dict_ldap->dict.error = DICT_ERR_RETRY;
                            break;
                        }
                    } else {
@@ -1283,17 +1283,17 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage *res,
                    default:
                        msg_warn("%s[%d]: search error %d: %s ", myname,
                                 recursion, rc, ldap_err2string(rc));
-                       dict_errno = DICT_ERR_RETRY;
+                       dict_ldap->dict.error = DICT_ERR_RETRY;
                        break;
                    }
 
                    if (resloop != 0)
                        ldap_msgfree(resloop);
 
-                   if (dict_errno != 0)
+                   if (dict_ldap->dict.error != 0)
                        break;
                }
-               if (msg_verbose && dict_errno == 0)
+               if (msg_verbose && dict_ldap->dict.error == 0)
                    msg_info("%s[%d]: search returned %d value(s) for"
                             " special result attribute %s",
                             myname, recursion, valcount, attr);
@@ -1302,7 +1302,7 @@ static void dict_ldap_get_values(DICT_LDAP *dict_ldap, LDAPMessage *res,
                msg_warn("%s[%d]: %s: Recursion limit exceeded"
                         " for special attribute %s=%s", myname, recursion,
                         dict_ldap->parser->name, attr, vals[0]->bv_val);
-               dict_errno = DICT_ERR_RETRY;
+               dict_ldap->dict.error = DICT_ERR_RETRY;
            }
            ldap_value_free_len(vals);
        }
@@ -1327,8 +1327,9 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
     static VSTRING *result;
     int     rc = 0;
     int     sizelimit;
+    int     domain_rc;
 
-    dict_errno = 0;
+    dict_ldap->dict.error = 0;
 
     if (msg_verbose)
        msg_info("%s: In dict_ldap_lookup", myname);
@@ -1358,12 +1359,15 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
      * addresses in domains on the list. This can significantly reduce the
      * load on the LDAP server.
      */
-    if (db_common_check_domain(dict_ldap->ctx, name) == 0) {
+    if ((domain_rc = db_common_check_domain(dict_ldap->ctx, name)) == 0) {
        if (msg_verbose)
            msg_info("%s: %s: Skipping lookup of key '%s': domain mismatch",
                     myname, dict_ldap->parser->name, name);
        return (0);
     }
+    if (domain_rc < 0)
+       DICT_ERR_VAL_RETURN(dict, domain_rc, (char *) 0);
+
 #define INIT_VSTR(buf, len) do { \
        if (buf == 0) \
            buf = vstring_alloc(len); \
@@ -1394,9 +1398,9 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
        dict_ldap_connect(dict_ldap);
 
        /*
-        * if dict_ldap_connect() set dict_errno, abort.
+        * if dict_ldap_connect() set dict_ldap->dict.error, abort.
         */
-       if (dict_errno)
+       if (dict_ldap->dict.error)
            return (0);
     } else if (msg_verbose)
        msg_info("%s: Using existing connection for LDAP source %s",
@@ -1414,7 +1418,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
        != LDAP_OPT_SUCCESS) {
        msg_warn("%s: %s: Unable to set query result size limit to %ld.",
                 myname, dict_ldap->parser->name, dict_ldap->size_limit);
-       dict_errno = DICT_ERR_RETRY;
+       dict_ldap->dict.error = DICT_ERR_RETRY;
        return (0);
     }
 
@@ -1463,9 +1467,9 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
        dict_ldap_connect(dict_ldap);
 
        /*
-        * if dict_ldap_connect() set dict_errno, abort.
+        * if dict_ldap_connect() set dict_ldap->dict.error, abort.
         */
-       if (dict_errno)
+       if (dict_ldap->dict.error)
            return (0);
 
        rc = search_st(dict_ldap->ld, vstring_str(base), dict_ldap->scope,
@@ -1513,7 +1517,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
        msg_warn("%s: %s: Search base '%s' not found: %d: %s",
                 myname, dict_ldap->parser->name,
                 vstring_str(base), rc, ldap_err2string(rc));
-       dict_errno = DICT_ERR_RETRY;
+       dict_ldap->dict.error = DICT_ERR_RETRY;
        break;
 
     default:
@@ -1534,7 +1538,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
        /*
         * And tell the caller to try again later.
         */
-       dict_errno = DICT_ERR_RETRY;
+       dict_ldap->dict.error = DICT_ERR_RETRY;
        break;
     }
 
@@ -1548,7 +1552,7 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
      * If we had an error, return nothing, Otherwise, return the result, if
      * any.
      */
-    return (VSTRING_LEN(result) > 0 && !dict_errno ? vstring_str(result) : 0);
+    return (VSTRING_LEN(result) > 0 && !dict_ldap->dict.error ? vstring_str(result) : 0);
 }
 
 /* dict_ldap_close - disassociate from data base */
index e6405e63371b4fb0c1b1705ec94a2fb884bda8a0..a60a20e8dfa52eb0682ffcb381e631432e0d6149 100644 (file)
@@ -89,7 +89,7 @@ typedef struct {
     VSTRING *clnt_buf;                 /* memcache client buffer */
     VSTRING *key_buf;                  /* lookup key */
     VSTRING *res_buf;                  /* lookup result */
-    int     mc_errno;                  /* memcache dict_errno */
+    int     error;                     /* memcache dict_errno */
     DICT   *backup;                    /* persistent backup */
 } DICT_MC;
 
@@ -129,22 +129,23 @@ typedef struct {
 
 /* dict_memcache_set - set memcache key/value */
 
-static void dict_memcache_set(DICT_MC *dict_mc, const char *value, int ttl)
+static int dict_memcache_set(DICT_MC *dict_mc, const char *value, int ttl)
 {
     VSTREAM *fp;
     int     count;
     int     data_len = strlen(value);
 
     /*
-     * If we can't retrieve it, then we must not store it.
+     * Return a permanent error if we can't store this data. This results in
+     * loss of information.
      */
-    dict_mc->mc_errno = DICT_ERR_RETRY;                /* XXX */
     if (data_len > dict_mc->max_data) {
        msg_warn("database %s:%s: data for key %s is too long (%s=%d) "
                 "-- not stored", DICT_TYPE_MEMCACHE, dict_mc->dict.name,
                 STR(dict_mc->key_buf), DICT_MC_NAME_MAX_DATA,
                 dict_mc->max_data);
-       return;
+       /* Not stored! */
+       DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_NONE, DICT_STAT_FAIL);
     }
     for (count = 0; count < dict_mc->max_tries; count++) {
        if (count > 0)
@@ -167,11 +168,11 @@ static void dict_memcache_set(DICT_MC *dict_mc, const char *value, int ttl)
                         STR(dict_mc->clnt_buf));
        } else {
            /* Victory! */
-           dict_mc->mc_errno = 0;
-           break;
+           DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_NONE, DICT_STAT_SUCCESS);
        }
        auto_clnt_recover(dict_mc->clnt);
     }
+    DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_RETRY, DICT_STAT_ERROR);
 }
 
 /* dict_memcache_get - get memcache key/value */
@@ -180,11 +181,8 @@ static const char *dict_memcache_get(DICT_MC *dict_mc)
 {
     VSTREAM *fp;
     long    todo;
-    const char *retval;
     int     count;
 
-    dict_mc->mc_errno = DICT_ERR_RETRY;
-    retval = 0;
     for (count = 0; count < dict_mc->max_tries; count++) {
        if (count > 0)
            sleep(dict_mc->err_pause);
@@ -198,8 +196,7 @@ static const char *dict_memcache_get(DICT_MC *dict_mc)
                         DICT_TYPE_MEMCACHE, dict_mc->dict.name);
        } else if (strcmp(STR(dict_mc->clnt_buf), "END") == 0) {
            /* Not found. */
-           dict_mc->mc_errno = 0;
-           break;
+           DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_NONE, (char *) 0);
        } else if (sscanf(STR(dict_mc->clnt_buf),
                          "VALUE %*s %*s %ld", &todo) != 1
                   || todo < 0 || todo > dict_mc->max_data) {
@@ -212,16 +209,14 @@ static const char *dict_memcache_get(DICT_MC *dict_mc)
                         dict_mc->dict.name);
        } else {
            /* Victory! */
-           retval = STR(dict_mc->res_buf);
-           dict_mc->mc_errno = 0;
            if (memcache_get(fp, dict_mc->clnt_buf, dict_mc->max_line) < 0
                || strcmp(STR(dict_mc->clnt_buf), "END") != 0)
                auto_clnt_recover(dict_mc->clnt);
-           break;
+           DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_NONE, STR(dict_mc->res_buf));
        }
        auto_clnt_recover(dict_mc->clnt);
     }
-    return (retval);
+    DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_RETRY, (char *) 0);
 }
 
 /* dict_memcache_del - delete memcache key/value */
@@ -230,9 +225,7 @@ static int dict_memcache_del(DICT_MC *dict_mc)
 {
     VSTREAM *fp;
     int     count;
-    int     retval = -1;
 
-    dict_mc->mc_errno = DICT_ERR_RETRY;
     for (count = 0; count < dict_mc->max_tries; count++) {
        if (count > 0)
            sleep(dict_mc->err_pause);
@@ -246,14 +239,10 @@ static int dict_memcache_del(DICT_MC *dict_mc)
                         DICT_TYPE_MEMCACHE, dict_mc->dict.name);
        } else if (strcmp(STR(dict_mc->clnt_buf), "DELETED") == 0) {
            /* Victory! */
-           dict_mc->mc_errno = 0;
-           retval = 0;
-           break;
+           DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_NONE, DICT_STAT_SUCCESS);
        } else if (strcmp(STR(dict_mc->clnt_buf), "NOT_FOUND") == 0) {
            /* Not found! */
-           dict_mc->mc_errno = 0;
-           retval = 1;
-           break;
+           DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_NONE, DICT_STAT_FAIL);
        } else {
            if (count > 0)
                msg_warn("database %s:%s: delete failed: %.30s",
@@ -262,7 +251,7 @@ static int dict_memcache_del(DICT_MC *dict_mc)
        }
        auto_clnt_recover(dict_mc->clnt);
     }
-    return (retval);
+    DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_RETRY, DICT_STAT_ERROR);
 }
 
 /* dict_memcache_prepare_key - prepare lookup key */
@@ -311,65 +300,67 @@ static int dict_memcache_valid_key(DICT_MC *dict_mc,
                                        void (*log_func) (const char *,...))
 {
     unsigned char *cp;
+    int     rc;
 
 #define DICT_MC_SKIP(why) do { \
        if (msg_verbose || log_func != msg_info) \
            log_func("%s: skipping %s for name \"%s\": %s", \
                     dict_mc->dict.name, operation, name, (why)); \
-       return(0); \
+       DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_NONE, 0); \
     } while (0)
 
     if (*name == 0)
        DICT_MC_SKIP("empty lookup key");
-    if (db_common_check_domain(dict_mc->dbc_ctxt, name) == 0)
+    if ((rc = db_common_check_domain(dict_mc->dbc_ctxt, name)) == 0)
        DICT_MC_SKIP("domain mismatch");
+    if (rc < 0)
+       DICT_ERR_VAL_RETURN(dict_mc, rc, 0);
     if (dict_memcache_prepare_key(dict_mc, name) == 0)
        DICT_MC_SKIP("empty lookup key expansion");
     for (cp = (unsigned char *) STR(dict_mc->key_buf); *cp; cp++)
        if (isascii(*cp) && isspace(*cp))
            DICT_MC_SKIP("name contains space");
 
-    return (1);
+    DICT_ERR_VAL_RETURN(dict_mc, DICT_ERR_NONE, 1);
 }
 
 /* dict_memcache_update - update memcache */
 
-static void dict_memcache_update(DICT *dict, const char *name,
-                                        const char *value)
+static int dict_memcache_update(DICT *dict, const char *name,
+                                       const char *value)
 {
     const char *myname = "dict_memcache_update";
     DICT_MC *dict_mc = (DICT_MC *) dict;
     DICT   *backup = dict_mc->backup;
-    int     backup_errno = 0;
+    int     upd_res;
 
     /*
      * Skip updates with an inapplicable key, noisily. This results in loss
      * of information.
      */
-    dict_errno = DICT_ERR_RETRY;
     if (dict_memcache_valid_key(dict_mc, name, "update", msg_warn) == 0)
-       return;
+       DICT_ERR_VAL_RETURN(dict, dict_mc->error, DICT_STAT_FAIL);
 
     /*
      * Update the memcache first.
      */
-    dict_memcache_set(dict_mc, value, dict_mc->mc_ttl);
+    upd_res = dict_memcache_set(dict_mc, value, dict_mc->mc_ttl);
+    dict->error = dict_mc->error;
 
     /*
      * Update the backup database last.
      */
     if (backup) {
-       dict_errno = 0;
-       backup->update(backup, name, value);
-       backup_errno = dict_errno;
+       upd_res = backup->update(backup, name, value);
+       dict->error = backup->error;
     }
     if (msg_verbose)
        msg_info("%s: %s: update key \"%s\"(%s) => \"%s\" %s",
                 myname, dict_mc->dict.name, name, STR(dict_mc->key_buf),
-                value, dict_mc->mc_errno ? "(memcache error)" :
-                backup_errno ? "(backup error)" : "(no error)");
+                value, dict_mc->error ? "(memcache error)" : (backup
+                      && backup->error) ? "(backup error)" : "(no error)");
 
-    dict_errno = (backup ? backup_errno : dict_mc->mc_errno);
+    return (upd_res);
 }
 
 /* dict_memcache_lookup - lookup memcache */
@@ -380,39 +371,39 @@ static const char *dict_memcache_lookup(DICT *dict, const char *name)
     DICT_MC *dict_mc = (DICT_MC *) dict;
     DICT   *backup = dict_mc->backup;
     const char *retval;
-    int     backup_errno = 0;
 
     /*
      * Skip lookups with an inapplicable key, silently. This is just asking
      * for information that cannot exist.
      */
-    dict_errno = 0;
     if (dict_memcache_valid_key(dict_mc, name, "lookup", msg_info) == 0)
-       return (0);
+       DICT_ERR_VAL_RETURN(dict, dict_mc->error, (char *) 0);
 
     /*
      * Search the memcache first.
      */
     retval = dict_memcache_get(dict_mc);
+    dict->error = dict_mc->error;
 
     /*
      * Search the backup database last. Update the memcache if the data is
      * found.
      */
-    if (retval == 0 && backup) {
-       retval = backup->lookup(backup, name);
-       backup_errno = dict_errno;
-       /* Update the cache. */
-       if (retval != 0)
-           dict_memcache_set(dict_mc, retval, dict_mc->mc_ttl);
+    if (backup) {
+       backup->error = 0;
+       if (retval == 0) {
+           retval = backup->lookup(backup, name);
+           dict->error = backup->error;
+           /* Update the cache. */
+           if (retval != 0)
+               dict_memcache_set(dict_mc, retval, dict_mc->mc_ttl);
+       }
     }
     if (msg_verbose)
        msg_info("%s: %s: key \"%s\"(%s) => %s",
                 myname, dict_mc->dict.name, name, STR(dict_mc->key_buf),
-                retval ? retval : dict_mc->mc_errno ? "(memcache error)" :
-                backup_errno ? "(backup error)" : "(not found)");
-
-    dict_errno = (backup ? backup_errno : dict_mc->mc_errno);
+                retval ? retval : dict_mc->error ? "(memcache error)" :
+             (backup && backup->error) ? "(backup error)" : "(not found)");
 
     return (retval);
 }
@@ -424,37 +415,34 @@ static int dict_memcache_delete(DICT *dict, const char *name)
     const char *myname = "dict_memcache_delete";
     DICT_MC *dict_mc = (DICT_MC *) dict;
     DICT   *backup = dict_mc->backup;
-    int     backup_errno = 0;
     int     del_res;
 
     /*
-     * Skip lookups with an inapplicable key, silently. This is just deleting
+     * Skip lookups with an inapplicable key, noisily. This is just deleting
      * information that cannot exist.
      */
-    dict_errno = 0;
     if (dict_memcache_valid_key(dict_mc, name, "delete", msg_info) == 0)
-       return (1);
+       DICT_ERR_VAL_RETURN(dict, dict_mc->error, dict_mc->error ?
+                           DICT_STAT_ERROR : DICT_STAT_FAIL);
 
     /*
      * Update the memcache first.
      */
     del_res = dict_memcache_del(dict_mc);
+    dict->error = dict_mc->error;
 
     /*
      * Update the persistent database last.
      */
     if (backup) {
-       dict_errno = 0;
        del_res = backup->delete(backup, name);
-       backup_errno = dict_errno;
+       dict->error = backup->error;
     }
     if (msg_verbose)
        msg_info("%s: %s: delete key \"%s\"(%s) => %s",
                 myname, dict_mc->dict.name, name, STR(dict_mc->key_buf),
-                dict_mc->mc_errno ? "(memcache error)" :
-                backup_errno ? "(backup error)" : "(no error)");
-
-    dict_errno = (backup ? backup_errno : dict_mc->mc_errno);
+                dict_mc->error ? "(memcache error)" : (backup
+                      && backup->error) ? "(backup error)" : "(no error)");
 
     return (del_res);
 }
@@ -464,15 +452,22 @@ static int dict_memcache_delete(DICT *dict, const char *name)
 static int dict_memcache_sequence(DICT *dict, int function, const char **key,
                                          const char **value)
 {
+    const char *myname = "dict_memcache_sequence";
     DICT_MC *dict_mc = (DICT_MC *) dict;
     DICT   *backup = dict_mc->backup;
+    int     seq_res;
 
     if (backup == 0) {
        msg_warn("database %s:%s: first/next support requires backup database",
                 DICT_TYPE_MEMCACHE, dict_mc->dict.name);
-       return (1);
+       DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_FAIL);
     } else {
-       return (backup->sequence(backup, function, key, value));
+       seq_res = backup->sequence(backup, function, key, value);
+       msg_info("%s: %s: key \"%s\" => %s",
+                myname, dict_mc->dict.name, *key ? *key : "(not found)",
+                *value ? *value : backup->error ? "(backup error)" :
+                "(not found)");
+       DICT_ERR_VAL_RETURN(dict, backup->error, seq_res);
     }
 }
 
index 8425cd72a1bbb8f61ed5282cab88580a7618db22..8f728523472b9e301abc4c169d2b154d0264c0f9 100644 (file)
@@ -71,7 +71,7 @@
 /*     the lookup result unchanged.
 /* .IP expansion_limit
 /*     Limit (if any) on the total number of lookup result values. Lookups which
-/*     exceed the limit fail with dict_errno=DICT_ERR_RETRY. Note that each
+/*     exceed the limit fail with dict->error=DICT_ERR_RETRY. Note that each
 /*     non-empty (and non-NULL) column of a multi-column result row counts as
 /*     one result.
 /* .IP table
@@ -237,13 +237,13 @@ typedef struct {
 #define TYPEINET                       (1<<1)
 
 #define RETRY_CONN_MAX                 100
-#define RETRY_CONN_INTV                        60              /* 1 minute */
-#define IDLE_CONN_INTV                 60              /* 1 minute */
+#define RETRY_CONN_INTV                        60      /* 1 minute */
+#define IDLE_CONN_INTV                 60      /* 1 minute */
 
 /* internal function declarations */
 static PLMYSQL *plmysql_init(ARGV *);
 static MYSQL_RES *plmysql_query(DICT_MYSQL *, const char *, VSTRING *, char *,
-                               char *, char *);
+                                       char *, char *);
 static void plmysql_dealloc(PLMYSQL *);
 static void plmysql_close_host(HOST *);
 static void plmysql_down_host(HOST *);
@@ -259,12 +259,12 @@ static HOST *host_init(const char *);
 static void dict_mysql_quote(DICT *dict, const char *name, VSTRING *result)
 {
     DICT_MYSQL *dict_mysql = (DICT_MYSQL *) dict;
-    int len = strlen(name);
-    int buflen = 2*len + 1;
+    int     len = strlen(name);
+    int     buflen = 2 * len + 1;
 
     /*
-     * We won't get integer overflows in 2*len + 1, because Postfix
-     * input keys have reasonable size limits, better safe than sorry.
+     * We won't get integer overflows in 2*len + 1, because Postfix input
+     * keys have reasonable size limits, better safe than sorry.
      */
     if (buflen < len)
        msg_panic("dict_mysql_quote: integer overflow in 2*%d+1", len);
@@ -286,8 +286,7 @@ static void dict_mysql_quote(DICT *dict, const char *name, VSTRING *result)
 static const char *dict_mysql_lookup(DICT *dict, const char *name)
 {
     const char *myname = "dict_mysql_lookup";
-    DICT_MYSQL *dict_mysql = (DICT_MYSQL *)dict;
-    PLMYSQL *pldb = dict_mysql->pldb;
+    DICT_MYSQL *dict_mysql = (DICT_MYSQL *) dict;
     MYSQL_RES *query_res;
     MYSQL_ROW row;
     static VSTRING *result;
@@ -298,8 +297,9 @@ static const char *dict_mysql_lookup(DICT *dict, const char *name)
     int     expansion;
     const char *r;
     db_quote_callback_t quote_func = dict_mysql_quote;
+    int     domain_rc;
 
-    dict_errno = 0;
+    dict->error = 0;
 
     /*
      * Optionally fold the key.
@@ -312,15 +312,17 @@ static const char *dict_mysql_lookup(DICT *dict, const char *name)
     }
 
     /*
-     * If there is a domain list for this map, then only search for
-     * addresses in domains on the list. This can significantly reduce
-     * the load on the server.
+     * If there is a domain list for this map, then only search for addresses
+     * in domains on the list. This can significantly reduce the load on the
+     * server.
      */
-    if (db_common_check_domain(dict_mysql->ctx, name) == 0) {
-        if (msg_verbose)
+    if ((domain_rc = db_common_check_domain(dict_mysql->ctx, name)) == 0) {
+       if (msg_verbose)
            msg_info("%s: Skipping lookup of '%s'", myname, name);
-        return (0);
+       return (0);
     }
+    if (domain_rc < 0)
+       DICT_ERR_VAL_RETURN(dict, domain_rc, (char *) 0);
 
 #define INIT_VSTR(buf, len) do { \
        if (buf == 0) \
@@ -333,28 +335,27 @@ static const char *dict_mysql_lookup(DICT *dict, const char *name)
 
     /*
      * Suppress the lookup if the query expansion is empty
-     *
-     * This initial expansion is outside the context of any
-     * specific host connection, we just want to check the
-     * key pre-requisites, so when quoting happens separately
-     * for each connection, we don't bother with quoting...
+     * 
+     * This initial expansion is outside the context of any specific host
+     * connection, we just want to check the key pre-requisites, so when
+     * quoting happens separately for each connection, we don't bother with
+     * quoting...
      */
 #if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 40000
     quote_func = 0;
 #endif
     if (!db_common_expand(dict_mysql->ctx, dict_mysql->query,
-                         name, 0, query, quote_func))
-        return (0);
-    
-    /* do the query - set dict_errno & cleanup if there's an error */
+                         name, 0, query, quote_func))
+       return (0);
+
+    /* do the query - set dict->error & cleanup if there's an error */
     if ((query_res = plmysql_query(dict_mysql, name, query,
                                   dict_mysql->dbname,
                                   dict_mysql->username,
                                   dict_mysql->password)) == 0) {
-       dict_errno = DICT_ERR_RETRY;
+       dict->error = DICT_ERR_RETRY;
        return (0);
     }
-
     numrows = mysql_num_rows(query_res);
     if (msg_verbose)
        msg_info("%s: retrieved %d rows", myname, numrows);
@@ -362,32 +363,31 @@ static const char *dict_mysql_lookup(DICT *dict, const char *name)
        mysql_free_result(query_res);
        return 0;
     }
-
     INIT_VSTR(result, 10);
 
-    for (expansion = i = 0; i < numrows && dict_errno == 0; i++) {
+    for (expansion = i = 0; i < numrows && dict->error == 0; i++) {
        row = mysql_fetch_row(query_res);
        for (j = 0; j < mysql_num_fields(query_res); j++) {
            if (db_common_expand(dict_mysql->ctx, dict_mysql->result_format,
-                                row[j], name, result, 0)
+                                row[j], name, result, 0)
                && dict_mysql->expansion_limit > 0
                && ++expansion > dict_mysql->expansion_limit) {
                msg_warn("%s: %s: Expansion limit exceeded for key: '%s'",
                         myname, dict_mysql->parser->name, name);
-               dict_errno = DICT_ERR_RETRY;
+               dict->error = DICT_ERR_RETRY;
                break;
            }
        }
     }
     mysql_free_result(query_res);
     r = vstring_str(result);
-    return ((dict_errno == 0 && *r) ? r : 0);
+    return ((dict->error == 0 && *r) ? r : 0);
 }
 
 /* dict_mysql_check_stat - check the status of a host */
 
 static int dict_mysql_check_stat(HOST *host, unsigned stat, unsigned type,
-                                time_t t)
+                                        time_t t)
 {
     if ((host->stat & stat) && (!type || host->type & type)) {
        /* try not to hammer the dead hosts too often */
@@ -429,7 +429,7 @@ static HOST *dict_mysql_find_host(PLMYSQL *PLDB, unsigned stat, unsigned type)
 /* dict_mysql_get_active - get an active connection */
 
 static HOST *dict_mysql_get_active(PLMYSQL *PLDB, char *dbname,
-                                  char *username, char *password)
+                                          char *username, char *password)
 {
     const char *myname = "dict_mysql_get_active";
     HOST   *host;
@@ -445,15 +445,15 @@ static HOST *dict_mysql_get_active(PLMYSQL *PLDB, char *dbname,
     }
 
     /*
-     * Try the remaining hosts.
-     * "count" is a safety net, in case the loop takes more than
-     * RETRY_CONN_INTV and the dead hosts are no longer skipped.
+     * Try the remaining hosts. "count" is a safety net, in case the loop
+     * takes more than RETRY_CONN_INTV and the dead hosts are no longer
+     * skipped.
      */
     while (--count > 0 &&
           ((host = dict_mysql_find_host(PLDB, STATUNTRIED | STATFAIL,
                                         TYPEUNIX)) != NULL ||
-          (host = dict_mysql_find_host(PLDB, STATUNTRIED | STATFAIL,
-                                       TYPEINET)) != NULL)) {
+           (host = dict_mysql_find_host(PLDB, STATUNTRIED | STATFAIL,
+                                        TYPEINET)) != NULL)) {
        if (msg_verbose)
            msg_info("%s: attempting to connect to host %s", myname,
                     host->hostname);
@@ -485,7 +485,7 @@ static void dict_mysql_event(int unused_event, char *context)
 
 static MYSQL_RES *plmysql_query(DICT_MYSQL *dict_mysql,
                                        const char *name,
-                                       VSTRING *query,
+                                       VSTRING *query,
                                        char *dbname,
                                        char *username,
                                        char *password)
@@ -497,9 +497,10 @@ static MYSQL_RES *plmysql_query(DICT_MYSQL *dict_mysql,
     while ((host = dict_mysql_get_active(PLDB, dbname, username, password)) != NULL) {
 
 #if defined(MYSQL_VERSION_ID) && MYSQL_VERSION_ID >= 40000
+
        /*
-        * The active host is used to escape strings in the
-        * context of the active connection's character encoding.
+        * The active host is used to escape strings in the context of the
+        * active connection's character encoding.
         */
        dict_mysql->active_host = host;
        VSTRING_RESET(query);
@@ -584,14 +585,14 @@ static void mysql_parse_config(DICT_MYSQL *dict_mysql, const char *mysqlcf)
     const char *myname = "mysqlname_parse";
     CFG_PARSER *p;
     VSTRING *buf;
-    int     i;
     char   *hosts;
-    
+
     p = dict_mysql->parser = cfg_parser_alloc(mysqlcf);
     dict_mysql->username = cfg_get_str(p, "user", "", 0, 0);
     dict_mysql->password = cfg_get_str(p, "password", "", 0, 0);
     dict_mysql->dbname = cfg_get_str(p, "dbname", "", 1, 0);
     dict_mysql->result_format = cfg_get_str(p, "result_format", "%s", 1, 0);
+
     /*
      * XXX: The default should be non-zero for safety, but that is not
      * backwards compatible.
@@ -600,10 +601,11 @@ static void mysql_parse_config(DICT_MYSQL *dict_mysql, const char *mysqlcf)
                                              "expansion_limit", 0, 0, 0);
 
     if ((dict_mysql->query = cfg_get_str(p, "query", NULL, 0, 0)) == 0) {
-        /*
-         * No query specified -- fallback to building it from components
-         * (old style "select %s from %s where %s")
-         */                 
+
+       /*
+        * No query specified -- fallback to building it from components (old
+        * style "select %s from %s where %s")
+        */
        buf = vstring_alloc(64);
        db_common_sql_build_query(buf, p);
        dict_mysql->query = vstring_export(buf);
@@ -619,8 +621,8 @@ static void mysql_parse_config(DICT_MYSQL *dict_mysql, const char *mysqlcf)
     db_common_parse_domain(p, dict_mysql->ctx);
 
     /*
-     * Maps that use substring keys should only be used with the full
-     * input key.
+     * Maps that use substring keys should only be used with the full input
+     * key.
      */
     if (db_common_dict_partial(dict_mysql->ctx))
        dict_mysql->dict.flags |= DICT_FLAG_PATTERN;
@@ -728,7 +730,6 @@ static HOST *host_init(const char *hostname)
        host->name = 0;
        host->type = TYPEUNIX;
     }
-
     if (msg_verbose > 1)
        msg_info("%s: host=%s, port=%d, type=%s", myname,
                 host->name ? host->name : "localhost",
@@ -740,7 +741,6 @@ static HOST *host_init(const char *hostname)
 
 static void dict_mysql_close(DICT *dict)
 {
-    int     i;
     DICT_MYSQL *dict_mysql = (DICT_MYSQL *) dict;
 
     plmysql_dealloc(dict_mysql->pldb);
@@ -751,7 +751,7 @@ static void dict_mysql_close(DICT *dict)
     myfree(dict_mysql->query);
     myfree(dict_mysql->result_format);
     if (dict_mysql->hosts)
-       argv_free(dict_mysql->hosts);
+       argv_free(dict_mysql->hosts);
     if (dict_mysql->ctx)
        db_common_free_ctx(dict_mysql->ctx);
     if (dict->fold_buf)
index c4c0e5fb87ed300b780413ab990d3a6261e0a3ad..a98a0c9798f537558bc6d2a93f435b3110c00963 100644 (file)
@@ -72,7 +72,7 @@
 /*     the lookup result unchanged.
 /* .IP expansion_limit
 /*     Limit (if any) on the total number of lookup result values. Lookups which
-/*     exceed the limit fail with dict_errno=DICT_ERR_RETRY. Note that each
+/*     exceed the limit fail with dict->error=DICT_ERR_RETRY. Note that each
 /*     non-empty (and non-NULL) column of a multi-column result row counts as
 /*     one result.
 /* .IP select_function
 #define TYPEINET                       (1<<1)
 
 #define RETRY_CONN_MAX                 100
-#define RETRY_CONN_INTV                        60              /* 1 minute */
-#define IDLE_CONN_INTV                 60              /* 1 minute */
+#define RETRY_CONN_INTV                        60      /* 1 minute */
+#define IDLE_CONN_INTV                 60      /* 1 minute */
 
 typedef struct {
     PGconn *db;
@@ -223,7 +223,7 @@ typedef struct {
 /* internal function declarations */
 static PLPGSQL *plpgsql_init(ARGV *);
 static PGSQL_RES *plpgsql_query(DICT_PGSQL *, const char *, VSTRING *, char *,
-                               char *, char *);
+                                       char *, char *);
 static void plpgsql_dealloc(PLPGSQL *);
 static void plpgsql_close_host(HOST *);
 static void plpgsql_down_host(HOST *);
@@ -238,21 +238,21 @@ static HOST *host_init(const char *);
 static void dict_pgsql_quote(DICT *dict, const char *name, VSTRING *result)
 {
     DICT_PGSQL *dict_pgsql = (DICT_PGSQL *) dict;
-    HOST  *active_host = dict_pgsql->active_host;
-    char  *myname = "dict_pgsql_quote";
-    size_t len = strlen(name);
-    size_t buflen = 2*len + 1;
-    int err = 1;
+    HOST   *active_host = dict_pgsql->active_host;
+    char   *myname = "dict_pgsql_quote";
+    size_t  len = strlen(name);
+    size_t  buflen = 2 * len + 1;
+    int     err = 1;
 
     if (active_host == 0)
        msg_panic("%s: bogus dict_pgsql->active_host", myname);
 
     /*
-     * We won't get arithmetic overflows in 2*len + 1, because Postfix
-     * input keys have reasonable size limits, better safe than sorry.
+     * We won't get arithmetic overflows in 2*len + 1, because Postfix input
+     * keys have reasonable size limits, better safe than sorry.
      */
     if (buflen <= len)
-       msg_panic("%s: arithmetic overflow in 2*%lu+1", 
+       msg_panic("%s: arithmetic overflow in 2*%lu+1",
                  myname, (unsigned long) len);
 
     /*
@@ -264,48 +264,48 @@ static void dict_pgsql_quote(DICT *dict, const char *name, VSTRING *result)
        return;
 
     /*
-     * Escape the input string, using PQescapeStringConn(), because
-     * the older PQescapeString() is not safe anymore, as stated by the
-     * documentation.
-     *
+     * Escape the input string, using PQescapeStringConn(), because the older
+     * PQescapeString() is not safe anymore, as stated by the documentation.
+     * 
      * From current libpq (8.1.4) documentation:
-     *
-     * PQescapeStringConn writes an escaped version of the from string 
-     * to the to buffer, escaping special characters so that they cannot
-     * cause any harm, and adding a terminating zero byte.
-     *
+     * 
+     * PQescapeStringConn writes an escaped version of the from string to the to
+     * buffer, escaping special characters so that they cannot cause any
+     * harm, and adding a terminating zero byte.
+     * 
      * ...
-     *
-     * The parameter from points to the first character of the string 
-     * that is to be escaped, and the length parameter gives the number 
-     * of bytes in this string. A terminating zero byte is not required,
-     * and should not be counted in length.
-     *
+     * 
+     * The parameter from points to the first character of the string that is to
+     * be escaped, and the length parameter gives the number of bytes in this
+     * string. A terminating zero byte is not required, and should not be
+     * counted in length.
+     * 
      * ...
-     *
-     * (The parameter) to shall point to a buffer that is able to hold 
-     * at least one more byte than twice the value of length, otherwise
-     * the behavior is undefined.
-     *
+     * 
+     * (The parameter) to shall point to a buffer that is able to hold at least
+     * one more byte than twice the value of length, otherwise the behavior
+     * is undefined.
+     * 
      * ...
-     *
+     * 
      * If the error parameter is not NULL, then *error is set to zero on
-     * success, nonzero on error ... The output string is still generated
-     * on error, but it can be expected that the server will reject it as
-     * malformed. On error, a suitable message is stored in the conn 
-     * object, whether or not error is NULL.
+     * success, nonzero on error ... The output string is still generated on
+     * error, but it can be expected that the server will reject it as
+     * malformed. On error, a suitable message is stored in the conn object,
+     * whether or not error is NULL.
      */
     VSTRING_SPACE(result, buflen);
     PQescapeStringConn(active_host->db, vstring_end(result), name, len, &err);
     if (err == 0) {
        VSTRING_SKIP(result);
     } else {
-       /* 
-        * PQescapeStringConn() failed. According to the docs, we still 
-        * have a valid, null-terminated output string, but we need not
-        * rely on this behavior.
+
+       /*
+        * PQescapeStringConn() failed. According to the docs, we still have
+        * a valid, null-terminated output string, but we need not rely on
+        * this behavior.
         */
-       msg_warn("dict pgsql: (host %s) cannot escape input string: %s", 
+       msg_warn("dict pgsql: (host %s) cannot escape input string: %s",
                 active_host->hostname, PQerrorMessage(active_host->db));
        active_host->stat = STATFAIL;
        VSTRING_TERMINATE(result);
@@ -328,7 +328,8 @@ static const char *dict_pgsql_lookup(DICT *dict, const char *name)
     int     numcols;
     int     expansion;
     const char *r;
-   
+    int     domain_rc;
+
     dict_pgsql = (DICT_PGSQL *) dict;
     pldb = dict_pgsql->pldb;
 
@@ -342,7 +343,7 @@ static const char *dict_pgsql_lookup(DICT *dict, const char *name)
     INIT_VSTR(query, 10);
     INIT_VSTR(result, 10);
 
-    dict_errno = 0;
+    dict->error = 0;
 
     /*
      * Optionally fold the key.
@@ -355,37 +356,38 @@ static const char *dict_pgsql_lookup(DICT *dict, const char *name)
     }
 
     /*
-     * If there is a domain list for this map, then only search for
-     * addresses in domains on the list. This can significantly reduce
-     * the load on the server.
+     * If there is a domain list for this map, then only search for addresses
+     * in domains on the list. This can significantly reduce the load on the
+     * server.
      */
-    if (db_common_check_domain(dict_pgsql->ctx, name) == 0) {
-        if (msg_verbose)
+    if ((domain_rc = db_common_check_domain(dict_pgsql->ctx, name)) == 0) {
+       if (msg_verbose)
            msg_info("%s: Skipping lookup of '%s'", myname, name);
-        return (0);
+       return (0);
     }
+    if (domain_rc < 0)
+       DICT_ERR_VAL_RETURN(dict, domain_rc, (char *) 0);
 
     /*
      * Suppress the actual lookup if the expansion is empty.
      * 
-     * This initial expansion is outside the context of any
-     * specific host connection, we just want to check the
-     * key pre-requisites, so when quoting happens separately
-     * for each connection, we don't bother with quoting...
+     * This initial expansion is outside the context of any specific host
+     * connection, we just want to check the key pre-requisites, so when
+     * quoting happens separately for each connection, we don't bother with
+     * quoting...
      */
     if (!db_common_expand(dict_pgsql->ctx, dict_pgsql->query,
                          name, 0, query, 0))
        return (0);
-    
-    /* do the query - set dict_errno & cleanup if there's an error */
+
+    /* do the query - set dict->error & cleanup if there's an error */
     if ((query_res = plpgsql_query(dict_pgsql, name, query,
                                   dict_pgsql->dbname,
                                   dict_pgsql->username,
                                   dict_pgsql->password)) == 0) {
-       dict_errno = DICT_ERR_RETRY;
+       dict->error = DICT_ERR_RETRY;
        return 0;
     }
-    
     numrows = PQntuples(query_res);
     if (msg_verbose)
        msg_info("%s: retrieved %d rows", myname, numrows);
@@ -395,29 +397,29 @@ static const char *dict_pgsql_lookup(DICT *dict, const char *name)
     }
     numcols = PQnfields(query_res);
 
-    for (expansion = i = 0; i < numrows && dict_errno == 0; i++) {
+    for (expansion = i = 0; i < numrows && dict->error == 0; i++) {
        for (j = 0; j < numcols; j++) {
            r = PQgetvalue(query_res, i, j);
            if (db_common_expand(dict_pgsql->ctx, dict_pgsql->result_format,
-                                r, name, result, 0)
+                                r, name, result, 0)
                && dict_pgsql->expansion_limit > 0
                && ++expansion > dict_pgsql->expansion_limit) {
                msg_warn("%s: %s: Expansion limit exceeded for key: '%s'",
                         myname, dict_pgsql->parser->name, name);
-               dict_errno = DICT_ERR_RETRY;
+               dict->error = DICT_ERR_RETRY;
                break;
            }
        }
     }
     PQclear(query_res);
     r = vstring_str(result);
-    return ((dict_errno == 0 && *r) ? r : 0);
+    return ((dict->error == 0 && *r) ? r : 0);
 }
 
 /* dict_pgsql_check_stat - check the status of a host */
 
 static int dict_pgsql_check_stat(HOST *host, unsigned stat, unsigned type,
-                                time_t t)
+                                        time_t t)
 {
     if ((host->stat & stat) && (!type || host->type & type)) {
        /* try not to hammer the dead hosts too often */
@@ -459,7 +461,7 @@ static HOST *dict_pgsql_find_host(PLPGSQL *PLDB, unsigned stat, unsigned type)
 /* dict_pgsql_get_active - get an active connection */
 
 static HOST *dict_pgsql_get_active(PLPGSQL *PLDB, char *dbname,
-                                  char *username, char *password)
+                                          char *username, char *password)
 {
     const char *myname = "dict_pgsql_get_active";
     HOST   *host;
@@ -475,15 +477,15 @@ static HOST *dict_pgsql_get_active(PLPGSQL *PLDB, char *dbname,
     }
 
     /*
-     * Try the remaining hosts.
-     * "count" is a safety net, in case the loop takes more than
-     * RETRY_CONN_INTV and the dead hosts are no longer skipped.
+     * Try the remaining hosts. "count" is a safety net, in case the loop
+     * takes more than RETRY_CONN_INTV and the dead hosts are no longer
+     * skipped.
      */
     while (--count > 0 &&
           ((host = dict_pgsql_find_host(PLDB, STATUNTRIED | STATFAIL,
-                                       TYPEUNIX)) != NULL ||
-          (host = dict_pgsql_find_host(PLDB, STATUNTRIED | STATFAIL,
-                                       TYPEINET)) != NULL)) {
+                                        TYPEUNIX)) != NULL ||
+           (host = dict_pgsql_find_host(PLDB, STATUNTRIED | STATFAIL,
+                                        TYPEINET)) != NULL)) {
        if (msg_verbose)
            msg_info("%s: attempting to connect to host %s", myname,
                     host->hostname);
@@ -526,9 +528,10 @@ static PGSQL_RES *plpgsql_query(DICT_PGSQL *dict_pgsql,
     ExecStatusType status;
 
     while ((host = dict_pgsql_get_active(PLDB, dbname, username, password)) != NULL) {
+
        /*
-        * The active host is used to escape strings in the
-        * context of the active connection's character encoding.
+        * The active host is used to escape strings in the context of the
+        * active connection's character encoding.
         */
        dict_pgsql->active_host = host;
        VSTRING_RESET(query);
@@ -543,40 +546,40 @@ static PGSQL_RES *plpgsql_query(DICT_PGSQL *dict_pgsql,
            continue;
        }
 
-       /* 
-        * Submit a command to the server. Be paranoid when processing
-        * the result set: try to enumerate every successful case, and
-        * reject everything else.
-        *
-        * From PostgreSQL 8.1.4 docs: (PQexec) returns a PGresult
-        * pointer or possibly a null pointer. A non-null pointer will
-        * generally be returned except in out-of-memory conditions or
-        * serious errors such as inability to send the command to the
-        * server.
+       /*
+        * Submit a command to the server. Be paranoid when processing the
+        * result set: try to enumerate every successful case, and reject
+        * everything else.
+        * 
+        * From PostgreSQL 8.1.4 docs: (PQexec) returns a PGresult pointer or
+        * possibly a null pointer. A non-null pointer will generally be
+        * returned except in out-of-memory conditions or serious errors such
+        * as inability to send the command to the server.
         */
        if ((res = PQexec(host->db, vstring_str(query))) != 0) {
+
            /*
-            * XXX Because non-null result pointer does not imply success,
-            * we need to check the command's result status.
-            *
-            * Section 28.3.1: A result of status PGRES_NONFATAL_ERROR
-            * will never be returned directly by PQexec or other query
-            * execution functions; results of this kind are instead 
-            * passed to the notice processor.
-            *
-            * PGRES_EMPTY_QUERY is being sent by the server when the
-            * query string is empty. The sanity-checking done by
-            * the Postfix infrastructure makes this case impossible,
-            * so we need not handle this situation explicitly.
+            * XXX Because non-null result pointer does not imply success, we
+            * need to check the command's result status.
+            * 
+            * Section 28.3.1: A result of status PGRES_NONFATAL_ERROR will
+            * never be returned directly by PQexec or other query execution
+            * functions; results of this kind are instead passed to the
+            * notice processor.
+            * 
+            * PGRES_EMPTY_QUERY is being sent by the server when the query
+            * string is empty. The sanity-checking done by the Postfix
+            * infrastructure makes this case impossible, so we need not
+            * handle this situation explicitly.
             */
            switch ((status = PQresultStatus(res))) {
            case PGRES_TUPLES_OK:
            case PGRES_COMMAND_OK:
                /* Success. */
                if (msg_verbose)
-                   msg_info("dict_pgsql: successful query from host %s", 
+                   msg_info("dict_pgsql: successful query from host %s",
                             host->hostname);
-               event_request_timer(dict_pgsql_event, (char *) host, 
+               event_request_timer(dict_pgsql_event, (char *) host,
                                    IDLE_CONN_INTV);
                return (res);
            case PGRES_FATAL_ERROR:
@@ -593,16 +596,17 @@ static PGSQL_RES *plpgsql_query(DICT_PGSQL *dict_pgsql,
                break;
            }
        } else {
-           /* 
-            * This driver treats null pointers like fatal, non-null
-            * result pointer errors, as suggested by the PostgreSQL 
-            * 8.1.4 documentation.
+
+           /*
+            * This driver treats null pointers like fatal, non-null result
+            * pointer errors, as suggested by the PostgreSQL 8.1.4
+            * documentation.
             */
            msg_warn("pgsql query failed: fatal error from host %s: %s",
                     host->hostname, PQerrorMessage(host->db));
        }
 
-       /* 
+       /*
         * XXX An error occurred. Clean up memory and skip this connection.
         */
        if (res != 0)
@@ -628,16 +632,14 @@ static void plpgsql_connect_single(HOST *host, char *dbname, char *username, cha
        plpgsql_down_host(host);
        return;
     }
-
     if (msg_verbose)
        msg_info("dict_pgsql: successful connection to host %s",
                 host->hostname);
 
     /*
-     * XXX Postfix does not send multi-byte characters. The following
-     * piece of code is an explicit statement of this fact, and the 
-     * database server should not accept multi-byte information after
-     * this point.
+     * XXX Postfix does not send multi-byte characters. The following piece
+     * of code is an explicit statement of this fact, and the database server
+     * should not accept multi-byte information after this point.
      */
     if (PQsetClientEncoding(host->db, "LATIN1") != 0) {
        msg_warn("dict_pgsql: cannot set the encoding to LATIN1, skipping %s",
@@ -645,7 +647,6 @@ static void plpgsql_connect_single(HOST *host, char *dbname, char *username, cha
        plpgsql_down_host(host);
        return;
     }
-
     /* Success. */
     host->stat = STATACTIVE;
 }
@@ -689,6 +690,7 @@ static void pgsql_parse_config(DICT_PGSQL *dict_pgsql, const char *pgsqlcf)
     dict_pgsql->password = cfg_get_str(p, "password", "", 0, 0);
     dict_pgsql->dbname = cfg_get_str(p, "dbname", "", 1, 0);
     dict_pgsql->result_format = cfg_get_str(p, "result_format", "%s", 1, 0);
+
     /*
      * XXX: The default should be non-zero for safety, but that is not
      * backwards compatible.
@@ -697,17 +699,18 @@ static void pgsql_parse_config(DICT_PGSQL *dict_pgsql, const char *pgsqlcf)
                                              "expansion_limit", 0, 0, 0);
 
     if ((dict_pgsql->query = cfg_get_str(p, "query", 0, 0, 0)) == 0) {
-         /*
-          * No query specified -- fallback to building it from components
-          * ( old style "select %s from %s where %s" )
-          */
+
+       /*
+        * No query specified -- fallback to building it from components (
+        * old style "select %s from %s where %s" )
+        */
        query = vstring_alloc(64);
        select_function = cfg_get_str(p, "select_function", 0, 0, 0);
        if (select_function != 0) {
            vstring_sprintf(query, "SELECT %s('%%s')", select_function);
            myfree(select_function);
        } else
-            db_common_sql_build_query(query, p);
+           db_common_sql_build_query(query, p);
        dict_pgsql->query = vstring_export(query);
     }
 
@@ -721,8 +724,8 @@ static void pgsql_parse_config(DICT_PGSQL *dict_pgsql, const char *pgsqlcf)
     db_common_parse_domain(p, dict_pgsql->ctx);
 
     /*
-     * Maps that use substring keys should only be used with the full
-     * input key.
+     * Maps that use substring keys should only be used with the full input
+     * key.
      */
     if (db_common_dict_partial(dict_pgsql->ctx))
        dict_pgsql->dict.flags |= DICT_FLAG_PATTERN;
@@ -765,7 +768,7 @@ DICT   *dict_pgsql_open(const char *name, int open_flags, int dict_flags)
     if (dict_pgsql->pldb == NULL)
        msg_fatal("couldn't intialize pldb!\n");
     dict_pgsql->dict.owner = cfg_get_owner(dict_pgsql->parser);
-    return (DICT_DEBUG(&dict_pgsql->dict));
+    return (DICT_DEBUG (&dict_pgsql->dict));
 }
 
 /* plpgsql_init - initalize a PGSQL database */
@@ -834,7 +837,7 @@ static void dict_pgsql_close(DICT *dict)
     myfree(dict_pgsql->query);
     myfree(dict_pgsql->result_format);
     if (dict_pgsql->hosts)
-       argv_free(dict_pgsql->hosts);
+       argv_free(dict_pgsql->hosts);
     if (dict_pgsql->ctx)
        db_common_free_ctx(dict_pgsql->ctx);
     if (dict->fold_buf)
index 12a41128f869520d74cd6f4e84db356f611caf56..86682f84d822d5d18865e5647398e886e4319e89 100644 (file)
@@ -149,15 +149,13 @@ static int dict_proxy_sequence(DICT *dict, int function,
            case PROXY_STAT_OK:
                *key = STR(dict_proxy->reskey);
                *value = STR(dict_proxy->result);
-               return (0);
+               DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_SUCCESS);
            case PROXY_STAT_NOKEY:
-               dict_errno = 0;
                *key = *value = 0;
-               return (1);
+               DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_FAIL);
            case PROXY_STAT_RETRY:
-               dict_errno = DICT_ERR_RETRY;
                *key = *value = 0;
-               return (1);
+               DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, DICT_STAT_ERROR);
            default:
                msg_warn("%s sequence failed for table \"%s\" function %d: "
                         "unexpected reply status %d",
@@ -223,13 +221,11 @@ static const char *dict_proxy_lookup(DICT *dict, const char *key)
                msg_fatal("%s service is not configured for table \"%s\"",
                          dict_proxy->service, dict->name);
            case PROXY_STAT_OK:
-               return (STR(dict_proxy->result));
+               DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, STR(dict_proxy->result));
            case PROXY_STAT_NOKEY:
-               dict_errno = 0;
-               return (0);
+               DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, (char *) 0);
            case PROXY_STAT_RETRY:
-               dict_errno = DICT_ERR_RETRY;
-               return (0);
+               DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, (char *) 0);
            default:
                msg_warn("%s lookup failed for table \"%s\" key \"%s\": "
                         "unexpected reply status %d",
@@ -243,7 +239,7 @@ static const char *dict_proxy_lookup(DICT *dict, const char *key)
 
 /* dict_proxy_update - update table entry */
 
-static void dict_proxy_update(DICT *dict, const char *key, const char *value)
+static int dict_proxy_update(DICT *dict, const char *key, const char *value)
 {
     const char *myname = "dict_proxy_update";
     DICT_PROXY *dict_proxy = (DICT_PROXY *) dict;
@@ -292,11 +288,11 @@ static void dict_proxy_update(DICT *dict, const char *key, const char *value)
                msg_fatal("%s update access is not configured for table \"%s\"",
                          dict_proxy->service, dict->name);
            case PROXY_STAT_OK:
-               dict_errno = 0;
-               return;
+               DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_SUCCESS);
+           case PROXY_STAT_NOKEY:
+               DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_FAIL);
            case PROXY_STAT_RETRY:
-               dict_errno = DICT_ERR_RETRY;
-               return;
+               DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, DICT_STAT_ERROR);
            default:
                msg_warn("%s update failed for table \"%s\" key \"%s\": "
                         "unexpected reply status %d",
@@ -359,13 +355,11 @@ static int dict_proxy_delete(DICT *dict, const char *key)
                msg_fatal("%s update access is not configured for table \"%s\"",
                          dict_proxy->service, dict->name);
            case PROXY_STAT_OK:
-               return 0;
-           case PROXY_STAT_RETRY:
-               dict_errno = DICT_ERR_RETRY;
-               return (-1);
+               DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_SUCCESS);
            case PROXY_STAT_NOKEY:
-               dict_errno = 0;
-               return (1);
+               DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_FAIL);
+           case PROXY_STAT_RETRY:
+               DICT_ERR_VAL_RETURN(dict, DICT_ERR_RETRY, DICT_STAT_ERROR);
            default:
                msg_warn("%s delete failed for table \"%s\" key \"%s\": "
                         "unexpected reply status %d",
index 008619c6eb31e4d03ed95b36f8bd82e5ad2880fc..acfcd408459e89b5e2251dd693a8c7f98d656ec8 100644 (file)
@@ -47,7 +47,7 @@
 /*     returning the lookup result unchanged.
 /* .IP expansion_limit
 /*     Limit (if any) on the total number of lookup result values.
-/*     Lookups which exceed the limit fail with dict_errno=DICT_ERR_RETRY.
+/*     Lookups which exceed the limit fail with dict->error=DICT_ERR_RETRY.
 /*     Note that each non-empty (and non-NULL) column of a
 /*     multi-column result row counts as one result.
 /* .IP "select_field, where_field, additional_conditions"
@@ -149,11 +149,12 @@ static const char *dict_sqlite_lookup(DICT *dict, const char *name)
     const char *retval;
     int     expansion = 0;
     int     status;
+    int     domain_rc;
 
     /*
      * In case of return without lookup (skipped key, etc.).
      */
-    dict_errno = 0;
+    dict->error = 0;
 
     /*
      * Don't frustrate future attempts to make Postfix UTF-8 transparent.
@@ -178,12 +179,14 @@ static const char *dict_sqlite_lookup(DICT *dict, const char *name)
     /*
      * Apply the optional domain filter for email address lookups.
      */
-    if (db_common_check_domain(dict_sqlite->ctx, name) == 0) {
+    if ((domain_rc = db_common_check_domain(dict_sqlite->ctx, name)) == 0) {
        if (msg_verbose)
            msg_info("%s: %s: Skipping lookup of '%s'",
                     myname, dict_sqlite->parser->name, name);
        return (0);
     }
+    if (domain_rc < 0)
+       DICT_ERR_VAL_RETURN(dict, domain_rc, (char *) 0);
 
     /*
      * Expand the query and query the database.
@@ -228,7 +231,7 @@ static const char *dict_sqlite_lookup(DICT *dict, const char *name)
                && ++expansion > dict_sqlite->expansion_limit) {
                msg_warn("%s: %s: Expansion limit exceeded for key '%s'",
                         myname, dict_sqlite->parser->name, name);
-               dict_errno = DICT_ERR_RETRY;
+               dict->error = DICT_ERR_RETRY;
                break;
            }
        }
@@ -237,7 +240,7 @@ static const char *dict_sqlite_lookup(DICT *dict, const char *name)
            msg_warn("%s: %s: SQL step failed for query '%s': %s\n",
                     myname, dict_sqlite->parser->name,
                     vstring_str(query), sqlite3_errmsg(dict_sqlite->db));
-           dict_errno = DICT_ERR_RETRY;
+           dict->error = DICT_ERR_RETRY;
            break;
        }
     }
@@ -250,7 +253,7 @@ static const char *dict_sqlite_lookup(DICT *dict, const char *name)
                  myname, dict_sqlite->parser->name,
                  vstring_str(query), sqlite3_errmsg(dict_sqlite->db));
 
-    return ((dict_errno == 0 && *(retval = vstring_str(result)) != 0) ?
+    return ((dict->error == 0 && *(retval = vstring_str(result)) != 0) ?
            retval : 0);
 }
 
index 79139add50de56a3cdcf9922d69791198989f20b..8433caaf76ce4a8d409bc3a3eb2eace666cb2ac0 100644 (file)
 /*     is the bit-wise OR of zero or more of the following:
 /* .IP MATCH_FLAG_PARENT
 /*     The hostname pattern foo.com matches itself and any name below
-/*      the domain foo.com. If this flag is cleared, foo.com matches itself
+/*     the domain foo.com. If this flag is cleared, foo.com matches itself
 /*     only, and .foo.com matches any name below the domain foo.com.
 /* .IP MATCH_FLAG_RETURN
-/*      Request that domain_list_match() returns zero with
-/*     dict_errno != 0, instead of raising a fatal error.
+/*     Request that domain_list_match() logs a warning and returns
+/*     zero, with list->error set to a non-zero dictionary error
+/*     code, instead of raising a fatal error.
 /* .PP
 /*     Specify MATCH_FLAG_NONE to request none of the above.
 /*     The second argument is a list of domain patterns, or the name of
@@ -115,7 +116,7 @@ int     main(int argc, char **argv)
     list = domain_list_init(MATCH_FLAG_PARENT | MATCH_FLAG_RETURN, argv[optind]);
     host = argv[optind + 1];
     vstream_printf("%s: %s\n", host, domain_list_match(list, host) ?
-                  "YES" : dict_errno == 0 ? "NO" : "ERROR");
+                  "YES" : list->error == 0 ? "NO" : "ERROR");
     vstream_fflush(VSTREAM_OUT);
     domain_list_free(list);
     return (0);
index e60a9e13a7ea15860a815bf8ba8521dd97de3b3e..4bff255b81d91edfffc6f712f5940e37f0182cf9 100644 (file)
@@ -181,7 +181,7 @@ int     flush_send_site(const char *site)
                          ATTR_TYPE_STR, MAIL_ATTR_REQ, FLUSH_REQ_SEND_SITE,
                                     ATTR_TYPE_STR, MAIL_ATTR_SITE, site,
                                     ATTR_TYPE_END);
-    else if (dict_errno == 0)
+    else if (flush_domains->error == 0)
        status = FLUSH_STAT_DENY;
     else
        status = FLUSH_STAT_FAIL;
@@ -238,7 +238,7 @@ int     flush_add(const char *site, const char *queue_id)
                                     ATTR_TYPE_STR, MAIL_ATTR_SITE, site,
                                 ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id,
                                     ATTR_TYPE_END);
-    else if (dict_errno == 0)
+    else if (flush_domains->error == 0)
        status = FLUSH_STAT_DENY;
     else
        status = FLUSH_STAT_FAIL;
index 6769daa8633453f7a553aa0b6e2eac0e34c2e0e0..ed8caab6dc74e3d9aa634331b26d5b709d21511a 100644 (file)
@@ -46,7 +46,7 @@
 /*     The copy includes the recipient address delimiter.
 /*     The caller is expected to pass the copy to myfree().
 /* DIAGNOSTICS
-/*     The global \fIdict_errno\fR is non-zero when the lookup
+/*     The maps->error value is non-zero when the lookup
 /*     should be tried again.
 /* SEE ALSO
 /*     maps(3), multi-dictionary search
@@ -100,6 +100,7 @@ const char *mail_addr_find(MAPS *path, const char *address, char **extp)
     char   *full_key;
     char   *bare_key;
     char   *saved_ext;
+    int     rc = 0;
 
     /*
      * Initialize.
@@ -120,7 +121,7 @@ const char *mail_addr_find(MAPS *path, const char *address, char **extp)
 #define FULL   0
 #define PARTIAL        DICT_FLAG_FIXED
 
-    if ((result = maps_find(path, full_key, FULL)) == 0 && dict_errno == 0
+    if ((result = maps_find(path, full_key, FULL)) == 0 && path->error == 0
       && bare_key != 0 && (result = maps_find(path, bare_key, PARTIAL)) != 0
        && extp != 0) {
        *extp = saved_ext;
@@ -131,13 +132,13 @@ const char *mail_addr_find(MAPS *path, const char *address, char **extp)
      * Try user+foo@$myorigin, user+foo@$mydestination or
      * user+foo@[${proxy,inet}_interfaces]. Then try with +foo stripped off.
      */
-    if (result == 0 && dict_errno == 0
+    if (result == 0 && path->error == 0
        && (ratsign = strrchr(full_key, '@')) != 0
        && (strcasecmp(ratsign + 1, var_myorigin) == 0
-           || resolve_local(ratsign + 1))) {
+           || (rc = resolve_local(ratsign + 1)) > 0)) {
        *ratsign = 0;
        result = maps_find(path, full_key, PARTIAL);
-       if (result == 0 && dict_errno == 0 && bare_key != 0) {
+       if (result == 0 && path->error == 0 && bare_key != 0) {
            if ((ratsign = strrchr(bare_key, '@')) == 0)
                msg_panic("%s: bare key botch", myname);
            *ratsign = 0;
@@ -147,12 +148,13 @@ const char *mail_addr_find(MAPS *path, const char *address, char **extp)
            }
        }
        *ratsign = '@';
-    }
+    } else if (rc < 0)
+       path->error = rc;
 
     /*
      * Try @domain.
      */
-    if (result == 0 && dict_errno == 0 && ratsign)
+    if (result == 0 && path->error == 0 && ratsign)
        result = maps_find(path, ratsign, PARTIAL);
 
     /*
@@ -161,7 +163,7 @@ const char *mail_addr_find(MAPS *path, const char *address, char **extp)
     if (msg_verbose)
        msg_info("%s: %s -> %s", myname, address,
                 result ? result :
-                dict_errno ? "(try again)" :
+                path->error ? "(try again)" :
                 "(not found)");
     myfree(full_key);
     if (bare_key)
@@ -205,7 +207,7 @@ int     main(int argc, char **argv)
        extent = 0;
        result = mail_addr_find(path, STR(buffer), &extent);
        vstream_printf("%s -> %s (%s)\n", STR(buffer), result ? result :
-                      dict_errno ? "(try again)" :
+                      path->error ? "(try again)" :
                       "(not found)", extent ? extent : "null extension");
        vstream_fflush(VSTREAM_OUT);
        if (extent)
index 6f835d39929b96c19c5faebefc45b4121e31ba26..e8bc6bc29af27475f5e7ff7566b0c758bc2637dd 100644 (file)
@@ -32,7 +32,7 @@
 /* DIAGNOSTICS
 /*     Warnings: map lookup returns a non-address result.
 /*
-/*     The global \fIdict_errno\fR is non-zero when the lookup
+/*     The path->error value is non-zero when the lookup
 /*     should be tried again.
 /* SEE ALSO
 /*     mail_addr_find(3), mail address matching
@@ -120,7 +120,7 @@ ARGV   *mail_addr_map(MAPS *path, const char *address, int propagate)
            msg_warn("%s lookup of %s returns non-address result \"%s\"",
                     path->title, address, string);
            argv = argv_free(argv);
-           dict_errno = DICT_ERR_RETRY;
+           path->error = DICT_ERR_RETRY;
        }
     }
 
@@ -130,7 +130,7 @@ ARGV   *mail_addr_map(MAPS *path, const char *address, int propagate)
     else {
        if (msg_verbose)
            msg_info("%s: %s -> %s", myname, address,
-                    dict_errno ? "(try again)" : "(not found)");
+                    path->error ? "(try again)" : "(not found)");
     }
 
     /*
index 1fc7847fcf72abdc5a99387978d3c448b49bc2ea..ed1b336d1a059b6e82592f45177594778d1b0755 100644 (file)
@@ -171,7 +171,6 @@ void    mail_conf_suck(void)
      * other kinds of trouble. Enter the configuration directory into the
      * default dictionary.
      */
-    dict_unknown_allowed = 1;
     if (var_config_dir)
        myfree(var_config_dir);
     if ((config_dir = getenv(CONF_ENV_PATH)) == 0)
index 95bf2c2e2458626dec3b8f1f8cd1056d50abb08c..bcb8857fc758d60f6624e476d789afe9e7bd523a 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20120102"
+#define MAIL_RELEASE_DATE      "20120108"
 #define MAIL_VERSION_NUMBER    "2.9"
 
 #ifdef SNAPSHOT
index a4e80d109e851dac3c0f84c4bb6c7d463f0df1d4..6f19eb8fc7fd5d674fc2fde253855d2b3f7b3383 100644 (file)
@@ -63,8 +63,9 @@
 /*     to open database. Warnings: null string lookup result.
 /*
 /*     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.
+/*     information was not found, and logs a warning when the
+/*     lookup failed due to error. The maps->error value indicates
+/*     if the last lookup failed due to error.
 /* BUGS
 /*     The dictionary name space is flat, so dictionary names allocated
 /*     by maps_create() may collide with dictionary names allocated by
@@ -166,7 +167,7 @@ const char *maps_find(MAPS *maps, const char *name, int flags)
     /*
      * In case of return without map lookup (empty name or no maps).
      */
-    dict_errno = 0;
+    maps->error = 0;
 
     /*
      * Temp. workaround, for buggy callers that pass zero-length keys when
@@ -186,20 +187,20 @@ const char *maps_find(MAPS *maps, const char *name, int flags)
                         maps->title, name);
                msg_warn("%s should return NO RESULT in case of NOT FOUND",
                         maps->title);
-               dict_errno = DICT_ERR_RETRY;
+               maps->error = DICT_ERR_RETRY;
                return (0);
            }
            if (msg_verbose)
                msg_info("%s: %s: %s: %s = %s", myname, maps->title,
                         *map_name, name, expansion);
            return (expansion);
-       } else if (dict_errno != 0) {
+       } else if ((maps->error = dict->error) != 0) {
            msg_warn("%s:%s lookup of %s failed", dict->type, dict->name, name);
            break;
        }
     }
     if (msg_verbose)
-       msg_info("%s: %s: %s: %s", myname, maps->title, name, dict_errno ?
+       msg_info("%s: %s: %s: %s", myname, maps->title, name, maps->error ?
                 "search aborted" : "not found");
     return (0);
 }
@@ -239,11 +240,11 @@ int     main(int argc, char **argv)
     maps = maps_create("whatever", argv[1], DICT_FLAG_LOCK);
 
     while (vstring_fgets_nonl(buf, VSTREAM_IN)) {
-       dict_errno = 99;
+       maps->error = 99;
        vstream_printf("\"%s\": ", vstring_str(buf));
        if ((result = maps_find(maps, vstring_str(buf), 0)) != 0) {
            vstream_printf("%s\n", result);
-       } else if (dict_errno != 0) {
+       } else if (maps->error != 0) {
            vstream_printf("lookup error\n");
        } else {
            vstream_printf("not found\n");
index 015811f699ebc7e1363b9f8e86ef38e77d111103..ccf2c6ac2b0a1d43076985e6f97ba9969997f3d9 100644 (file)
@@ -22,6 +22,7 @@
 typedef struct MAPS {
     char   *title;
     struct ARGV *argv;
+    int     error;                     /* last request only */
 } MAPS;
 
 extern MAPS *maps_create(const char *, const char *, int);
index 7b51eddf70ac43e01075a6d3578fb4bc52a2e338..59c796e840e5e186be0b5403b436d643f08747c6 100644 (file)
@@ -14,7 +14,7 @@
  /*
   * Utility library.
   */
-#include <match_ops.h>
+#include <match_list.h>
 
  /*
   * External interface.
index 969b2a733aa3fb9d4430d1d90d7db4b3e0c4c923..d74a9125d3176873e9bd467b27a24574dbd3b95c 100644 (file)
@@ -41,6 +41,7 @@ extern MKMAP *mkmap_hash_open(const char *);
 extern MKMAP *mkmap_btree_open(const char *);
 extern MKMAP *mkmap_sdbm_open(const char *);
 extern MKMAP *mkmap_proxy_open(const char *);
+extern MKMAP *mkmap_fail_open(const char *);
 
 /* LICENSE
 /* .ad
diff --git a/postfix/src/global/mkmap_fail.c b/postfix/src/global/mkmap_fail.c
new file mode 100644 (file)
index 0000000..c35fe50
--- /dev/null
@@ -0,0 +1,53 @@
+/*++
+/* NAME
+/*     mkmap_fail 3
+/* SUMMARY
+/*     create or open database, fail: style
+/* SYNOPSIS
+/*     #include <mkmap.h>
+/*
+/*     MKMAP   *mkmap_fail_open(path)
+/*     const char *path;
+/*
+/* DESCRIPTION
+/*     This module implements support for error testing postmap
+/*     and postalias with the fail: table type.
+/* SEE ALSO
+/*     dict_fail(3), fail dictionary interface.
+/* 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>
+
+/* Utility library. */
+
+#include <mymalloc.h>
+#include <dict.h>
+
+/* Application-specific. */
+
+#include <mkmap.h>
+#include <dict_fail.h>
+
+ /*
+  * Dummy module: the dict_fail module has all the functionality built-in.
+  */
+MKMAP  *mkmap_fail_open(const char *unused_path)
+{
+    MKMAP  *mkmap = (MKMAP *) mymalloc(sizeof(*mkmap));
+
+    mkmap->open = dict_fail_open;
+    mkmap->after_open = 0;
+    mkmap->after_close = 0;
+    return (mkmap);
+}
index 69a0d5727a987d9270de8bdef0135d0726a0e685..d939d443d8ab9fbf5eae767aa1a69369adc35661 100644 (file)
@@ -67,6 +67,7 @@
 #include <dict_dbm.h>
 #include <dict_sdbm.h>
 #include <dict_proxy.h>
+#include <dict_fail.h>
 #include <sigdelay.h>
 #include <mymalloc.h>
 
@@ -100,6 +101,7 @@ static const MKMAP_OPEN_INFO mkmap_types[] = {
     DICT_TYPE_HASH, mkmap_hash_open,
     DICT_TYPE_BTREE, mkmap_btree_open,
 #endif
+    DICT_TYPE_FAIL, mkmap_fail_open,
     0,
 };
 
@@ -109,7 +111,10 @@ static const MKMAP_OPEN_INFO mkmap_types[] = {
 
 void    mkmap_append(MKMAP *mkmap, const char *key, const char *value)
 {
-    dict_put(mkmap->dict, key, value);
+    DICT   *dict = mkmap->dict;
+
+    if (dict_put(dict, key, value) != 0 && dict->error != 0)
+       msg_fatal("%s:%s: update failed", dict->type, dict->name);
 }
 
 /* mkmap_close - close database */
index b3c42d41efbcb78234177636bf647c612c4a39bb..66a1fb934827a4c4d2eb4441758e7c58a5d22988 100644 (file)
@@ -46,8 +46,9 @@
 /*     the domain foo.com. If this flag is cleared, foo.com matches itself
 /*     only, and .foo.com matches any name below the domain foo.com.
 /* .IP MATCH_FLAG_RETURN
-/*     Request that namadr_list_match() returns zero with
-/*     dict_errno != 0, instead of raising a fatal error.
+/*     Request that namadr_list_match() logs a warning and returns
+/*     zero with list->error set to a non-zero dictionary error
+/*     code, instead of raising a fatal error.
 /* .PP
 /*     Specify MATCH_FLAG_NONE to request none of the above.
 /*     The second argument is a list of patterns, or the absolute
@@ -124,7 +125,7 @@ int     main(int argc, char **argv)
     addr = argv[optind + 2];
     vstream_printf("%s/%s: %s\n", host, addr,
                   namadr_list_match(list, host, addr) ?
-                  "YES" : dict_errno == 0 ? "NO" : "ERROR");
+                  "YES" : list->error == 0 ? "NO" : "ERROR");
     vstream_fflush(VSTREAM_OUT);
     namadr_list_free(list);
     return (0);
index 09fcf94d1f25eefb019a7700cac3576dfcb481e5..98d04b2a8c8e283a578178e75e756c72a4a01c58 100644 (file)
@@ -16,9 +16,9 @@
 /*     against the domains, files or tables listed in $mydestination,
 /*     or by a match of an [address-literal] against of the network
 /*     addresses listed in $inet_interfaces or in $proxy_interfaces.
-/*     The result is non-zero if the domain matches the list of local
-/*     domains and IP addresses, 0 when it does not match or in case
-/*     of error (in the latter case dict_errno is non-zero).
+/*     The result is > 0 if the domain matches the list of local
+/*     domains and IP addresses, 0 when it does not match, and < 0
+/*     in case of error.
 /*
 /*     resolve_local_init() performs initialization. If this routine is
 /*     not called explicitly ahead of time, it will be called on the fly.
@@ -96,12 +96,6 @@ int     resolve_local(const char *addr)
     if (resolve_local_list == 0)
        resolve_local_init();
 
-    /*
-     * In case of return without table lookup (empty address, malformed
-     * address, empty destination list)
-     */
-    dict_errno = 0;
-
     /*
      * Strip one trailing dot but not dot-dot.
      * 
@@ -123,8 +117,8 @@ int     resolve_local(const char *addr)
      */
     if (string_list_match(resolve_local_list, saved_addr))
        RETURN(1);
-    if (dict_errno != 0)
-       RETURN(0);
+    if (resolve_local_list->error != 0)
+       RETURN(resolve_local_list->error);
 
     /*
      * Compare the destination against the list of interface addresses that
@@ -180,15 +174,16 @@ int     resolve_local(const char *addr)
 
 int     main(int argc, char **argv)
 {
+    int     rc;
+
     if (argc != 3)
        msg_fatal("usage: %s mydestination domain", argv[0]);
     mail_conf_read();
     myfree(var_mydest);
     var_mydest = mystrdup(argv[1]);
-    dict_errno = 99;
-    vstream_printf("mydestination=%s destination=%s %s\n",
-                  argv[1], argv[2], resolve_local(argv[2]) ? "YES" :
-                  dict_errno == 0 ? "NO" : "ERROR");
+    vstream_printf("mydestination=%s destination=%s %s\n", argv[1], argv[2],
+                  (rc = resolve_local(argv[2])) > 0 ? "YES" :
+                  rc == 0 ? "NO" : "ERROR");
     vstream_fflush(VSTREAM_OUT);
     return (0);
 }
index 9d9fa495051e5d4cb81a578e965fe27a15296d15..4ef0eec6920f3e9ea65facb1ab779ba559ce892a 100644 (file)
@@ -169,7 +169,7 @@ int     server_acl_eval(const char *client_addr, SERVER_ACL * intern_acl,
        } else if (STREQ(acl, SERVER_ACL_NAME_WL_MYNETWORKS)) {
            if (addr_match_list_match(server_acl_mynetworks, client_addr))
                return (SERVER_ACL_ACT_PERMIT);
-           if (dict_errno != 0) {
+           if (server_acl_mynetworks->error != 0) {
                msg_warn("%s: %s: mynetworks lookup error -- ignoring the "
                         "remainder of this access list", origin, acl);
                return (SERVER_ACL_ACT_ERROR);
@@ -190,7 +190,7 @@ int     server_acl_eval(const char *client_addr, SERVER_ACL * intern_acl,
                }
                if (ret != SERVER_ACL_ACT_DUNNO)
                    return (ret);
-           } else if (dict_errno != 0) {
+           } else if (dict->error != 0) {
                msg_warn("%s: %s: table lookup error -- ignoring the remainder "
                         "of this access list", origin, acl);
                return (SERVER_ACL_ACT_ERROR);
index 4b84ace9f3449be95508b797f96dd7bc40bae4f5..a24e4e179da534db2f5d3dd428a1fa505d6222bb 100644 (file)
@@ -34,8 +34,9 @@
 /*     string_list_init() performs initializations. The first argument
 /*     is a bit-wise OR of zero or more of following:
 /* .IP MATCH_FLAG_RETURN
-/*     Request that string_list_match() returns zero with
-/*     dict_errno != 0, instead of raising a fatal error.
+/*     Request that string_list_match() logs a warning and returns
+/*     zero with list->error set to a non-zero dictionary error
+/*     code, instead of raising a fatal error.
 /* .PP
 /*     Specify MATCH_FLAG_NONE to request none of the above.
 /*     The second argument specifies a list of string patterns.
@@ -105,10 +106,10 @@ int     main(int argc, char **argv)
     }
     if (argc != optind + 2)
        usage(argv[0]);
-    list = string_list_init(MATCH_FLAG_NONE | MATCH_FLAG_RETURN, argv[optind]);
+    list = string_list_init(MATCH_FLAG_RETURN, argv[optind]);
     string = argv[optind + 1];
     vstream_printf("%s: %s\n", string, string_list_match(list, string) ?
-                  "YES" : dict_errno == 0 ? "NO" : "ERROR");
+                  "YES" : list->error == 0 ? "NO" : "ERROR");
     vstream_fflush(VSTREAM_OUT);
     string_list_free(list);
     return (0);
index a2ead57956fa142f42ea3a10fb45ffaffb15ff1e..ca5546ec9d1ac686e89a2aeba9bb887259b5b5b6 100644 (file)
@@ -273,7 +273,7 @@ int     deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr,
             * Deliver.
             */
            alias_count = 0;
-           if (dict_errno != 0) {
+           if (owner != 0 && alias_maps->error != 0) {
                dsb_simple(state.msg_attr.why, "4.3.0",
                           "alias database unavailable");
                *statusp = defer_append(BOUNCE_FLAGS(state.request),
@@ -369,7 +369,9 @@ int     deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr,
         * If the alias database was inaccessible for some reason, defer
         * further delivery for the current top-level recipient.
         */
-       if (dict_errno != 0) {
+       if (alias_result == 0 && dict->error != 0) {
+           msg_warn("%s:%s: lookup of '%s' failed",
+                    dict->type, dict->name, name);
            dsb_simple(state.msg_attr.why, "4.3.0",
                       "alias database unavailable");
            *statusp = defer_append(BOUNCE_FLAGS(state.request),
index 6938f3d509739dcc348a727f7d5a10aed4ed2158..8d1670c805181b98383a59024f3d9bb1c7ce427d 100644 (file)
@@ -98,7 +98,6 @@ int     bounce_workaround(LOCAL_STATE state)
        char   *stripped_recipient;
        char   *owner_alias;
        const char *owner_expansion;
-       int     saved_dict_errno;
 
 #define FIND_OWNER(lhs, rhs, addr) { \
        lhs = concatenate("owner-", addr, (char *) 0); \
@@ -106,9 +105,8 @@ int     bounce_workaround(LOCAL_STATE state)
        rhs = maps_find(alias_maps, lhs, DICT_FLAG_NONE); \
     }
 
-       dict_errno = 0;
        FIND_OWNER(owner_alias, owner_expansion, state.msg_attr.rcpt.address);
-       if ((saved_dict_errno = dict_errno) == 0 && owner_expansion == 0
+       if (alias_maps->error == 0 && owner_expansion == 0
            && (stripped_recipient = strip_addr(state.msg_attr.rcpt.address,
                                                (char **) 0,
                                                *var_rcpt_delim)) != 0) {
@@ -116,14 +114,14 @@ int     bounce_workaround(LOCAL_STATE state)
            FIND_OWNER(owner_alias, owner_expansion, stripped_recipient);
            myfree(stripped_recipient);
        }
-       if ((saved_dict_errno = dict_errno) == 0 && owner_expansion != 0) {
+       if (alias_maps->error == 0 && owner_expansion != 0) {
            canon_owner = canon_addr_internal(vstring_alloc(10),
                                              var_exp_own_alias ?
                                              owner_expansion : owner_alias);
            SET_OWNER_ATTR(state.msg_attr, STR(canon_owner), state.level);
        }
        myfree(owner_alias);
-       if (saved_dict_errno != 0)
+       if (alias_maps->error != 0)
            /* At this point, canon_owner == 0. */
            return (defer_append(BOUNCE_FLAGS(state.request),
                                 BOUNCE_ATTR(state.msg_attr)));
index 5d1f200d3ab447625cc8b323b11934f5e19dc990..ca107724196861af4d9243e2646c1dbaebc0f7a3 100644 (file)
@@ -278,15 +278,14 @@ int     deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
        transp_maps = maps_create(VAR_MBOX_TRANSP_MAPS, var_mbox_transp_maps,
                                  DICT_FLAG_LOCK | DICT_FLAG_NO_REGSUB);
     /* The -1 is a hint for the down-stream deliver_completed() function. */
-    dict_errno = 0;
-    if (*var_mbox_transp_maps
+    if (transp_maps
        && (map_transport = maps_find(transp_maps, state.msg_attr.user,
                                      DICT_FLAG_NONE)) != 0) {
        state.msg_attr.rcpt.offset = -1L;
        *statusp = deliver_pass(MAIL_CLASS_PRIVATE, map_transport,
                                state.request, &state.msg_attr.rcpt);
        return (YES);
-    } else if (dict_errno != 0) {
+    } else if (transp_maps && transp_maps->error != 0) {
        /* Details in the logfile. */
        dsb_simple(state.msg_attr.why, "4.3.0", "table lookup failure");
        *statusp = defer_append(BOUNCE_FLAGS(state.request),
@@ -334,12 +333,10 @@ int     deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
        cmd_maps = maps_create(VAR_MAILBOX_CMD_MAPS, var_mailbox_cmd_maps,
                               DICT_FLAG_LOCK | DICT_FLAG_PARANOID);
 
-    dict_errno = 0;
-    if (*var_mailbox_cmd_maps
-       && (map_command = maps_find(cmd_maps, state.msg_attr.user,
+    if (cmd_maps && (map_command = maps_find(cmd_maps, state.msg_attr.user,
                                    DICT_FLAG_NONE)) != 0) {
        status = deliver_command(state, usr_attr, map_command);
-    } else if (dict_errno != 0) {
+    } else if (cmd_maps && cmd_maps->error != 0) {
        /* Details in the logfile. */
        dsb_simple(state.msg_attr.why, "4.3.0", "table lookup failure");
        status = defer_append(BOUNCE_FLAGS(state.request),
index 57e49af849e2d0ca9ae187fb401ba128d846e422..91c338c1bc4c383dc1b089f7041dfa627eb59596 100644 (file)
@@ -110,14 +110,13 @@ int     deliver_unknown(LOCAL_STATE state, USER_ATTR usr_attr)
        transp_maps = maps_create(VAR_FBCK_TRANSP_MAPS, var_fbck_transp_maps,
                                  DICT_FLAG_LOCK | DICT_FLAG_NO_REGSUB);
     /* The -1 is a hint for the down-stream deliver_completed() function. */
-    dict_errno = 0;
-    if (*var_fbck_transp_maps
+    if (transp_maps
        && (map_transport = maps_find(transp_maps, state.msg_attr.user,
                                      DICT_FLAG_NONE)) != 0) {
        state.msg_attr.rcpt.offset = -1L;
        return (deliver_pass(MAIL_CLASS_PRIVATE, map_transport,
                             state.request, &state.msg_attr.rcpt));
-    } else if (dict_errno != 0) {
+    } else if (transp_maps && transp_maps->error != 0) {
        /* Details in the logfile. */
        dsb_simple(state.msg_attr.why, "4.3.0", "table lookup failure");
        return (defer_append(BOUNCE_FLAGS(state.request),
index a10bdd1f71e5e99f021b0940ce9b49e3698fc756..c6161b8574df878b71c2580afee22230c654c03f 100644 (file)
@@ -22,7 +22,7 @@ Makefile: Makefile.in
 
 update: ../../bin/$(PROG)
 
-tests: test1 test2
+tests: test1 test2 fail_test
 
 root_tests:
 
@@ -52,6 +52,11 @@ test2:       $(PROG) map.in map-abc2.ref map-ghi2.ref map-uABC2.ref
        done
        rm -f map.in.db
 
+fail_test: $(PROG) aliases fail_test.in fail_test.ref
+       -sh fail_test.in > fail_test.tmp 2>&1 || exit 0
+       diff fail_test.ref fail_test.tmp
+       rm -f fail_test.tmp
+
 ../../bin/$(PROG): $(PROG)
        cp $(PROG) ../../bin
 
diff --git a/postfix/src/postalias/aliases b/postfix/src/postalias/aliases
new file mode 100644 (file)
index 0000000..a2a278d
--- /dev/null
@@ -0,0 +1 @@
+xx: yy
diff --git a/postfix/src/postalias/fail_test.in b/postfix/src/postalias/fail_test.in
new file mode 100644 (file)
index 0000000..1502c2c
--- /dev/null
@@ -0,0 +1,7 @@
+./postalias -q xx fail:aliases
+echo xx | ./postalias -q - fail:aliases
+./postalias -d xx fail:aliases
+echo xx | ./postalias -d - fail:aliases
+./postalias -s fail:aliases
+./postalias -i fail:aliases < aliases
+./postalias fail:aliases
diff --git a/postfix/src/postalias/fail_test.ref b/postfix/src/postalias/fail_test.ref
new file mode 100644 (file)
index 0000000..64d2eef
--- /dev/null
@@ -0,0 +1,7 @@
+postalias: fatal: fail:aliases: query error: Unknown error: 0
+postalias: fatal: fail:aliases: query error: Unknown error: 0
+postalias: fatal: fail:aliases: delete error: Unknown error: 0
+postalias: fatal: fail:aliases: delete error: Unknown error: 0
+postalias: fatal: fail:aliases: sequence error: Unknown error: 0
+postalias: fatal: fail:aliases: write error: Unknown error: 0
+postalias: fatal: fail:aliases: write error: Unknown error: 0
index 9b17d0207f3a73988c9f1989d7696d9f80adc750..a031ef73d4787a46322e780073792a2cd9a287cf 100644 (file)
 /* .IP \fBhash\fR
 /*     The output is a hashed file, named \fIfile_name\fB.db\fR.
 /*     This is available on systems with support for \fBdb\fR databases.
+/* .IP \fBfail\fR
+/*     A table that reliably fails all requests. The lookup table
+/*     name is used for logging only. This table exists to simplify
+/*     Postfix error tests.
 /* .IP \fBsdbm\fR
 /*     The output consists of two files, named \fIfile_name\fB.pag\fR and
 /*     \fIfile_name\fB.dir\fR.
@@ -376,6 +380,9 @@ static void postalias(char *map_type, char *path_name, int postalias_flags,
         * Store the value under a case-insensitive key.
         */
        mkmap_append(mkmap, STR(key_buffer), STR(value_buffer));
+       if (mkmap->dict->error)
+           msg_fatal("%s:%s: write error: %m",
+                     mkmap->dict->type, mkmap->dict->name);
     }
 
     /*
@@ -390,6 +397,9 @@ static void postalias(char *map_type, char *path_name, int postalias_flags,
      * sendmail.
      */
     mkmap_append(mkmap, "@", "@");
+    if (mkmap->dict->error)
+       msg_fatal("%s:%s: write error: %m",
+                 mkmap->dict->type, mkmap->dict->name);
 
     /*
      * NIS compatibility: add time and master info. Unlike other information,
@@ -466,6 +476,9 @@ static int postalias_queries(VSTREAM *in, char **maps, const int map_count,
                found = 1;
                break;
            }
+           if (dicts[n]->error)
+               msg_fatal("%s:%s: query error: %m",
+                         dicts[n]->type, dicts[n]->name);
        }
     }
     if (found)
@@ -501,6 +514,8 @@ static int postalias_query(const char *map_type, const char *map_name,
        }
        vstream_printf("%s\n", value);
     }
+    if (dict->error)
+        msg_fatal("%s:%s: query error: %m", dict->type, dict->name);
     vstream_fflush(VSTREAM_OUT);
     dict_close(dict);
     return (value != 0);
@@ -542,9 +557,14 @@ static int postalias_deletes(VSTREAM *in, char **maps, const int map_count,
     /*
      * Perform all requests.
      */
-    while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF)
-       for (n = 0; n < map_count; n++)
+    while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF) {
+       for (n = 0; n < map_count; n++) {
            found |= (dict_del(dicts[n], STR(keybuf)) == 0);
+            if (dicts[n]->error)
+                msg_fatal("%s:%s: delete error: %m",
+                          dicts[n]->type, dicts[n]->name);
+        }
+    }
 
     /*
      * Cleanup.
@@ -573,6 +593,8 @@ static int postalias_delete(const char *map_type, const char *map_name,
        open_flags = O_RDWR;
     dict = dict_open3(map_type, map_name, open_flags, dict_flags);
     status = dict_del(dict, key);
+    if (dict->error)
+        msg_fatal("%s:%s: delete error: %m", dict->type, dict->name);
     dict_close(dict);
     return (status == 0);
 }
@@ -604,6 +626,8 @@ static void postalias_seq(const char *map_type, const char *map_name,
        }
        vstream_printf("%s:     %s\n", key, value);
     }
+    if (dict->error)
+        msg_fatal("%s:%s: sequence error: %m", dict->type, dict->name);
     vstream_fflush(VSTREAM_OUT);
     dict_close(dict);
 }
index d742557b200cc68922c4fa5f29245ff072770a8f..6672b694d773b49f93344d364f2265c936b44acb 100644 (file)
 /*     useful someday.
 /* .IP \fBfail\fR
 /*     A table that reliably fails all requests. The lookup table
-/*     name provides the internal error result code. This table
-/*     exists to simplify Postfix error tests.
+/*     name is used for logging. This table exists to simplify
+/*     Postfix error tests.
 /* .IP \fBhash\fR
 /*     An indexed file type based on hashing.
 /*     This is available on systems with support for Berkeley DB
index d566869d886f14037ec931294c9f8ce101e30534..9411d7dc4a677208bf5834def894fd377e99451e 100644 (file)
@@ -105,7 +105,6 @@ void    read_parameters(void)
      * A direct rip-off of mail_conf_read(). XXX Avoid code duplication by
      * better code decomposition.
      */
-    dict_unknown_allowed = 1;
     set_config_dir();
     path = concatenate(var_config_dir, "/", MAIN_CONF_FILE, (char *) 0);
     dict_load_file(CONFIG_DICT, path);
index 8d876df715a02ec5e36c908487edc61fee98933a..2684a5d77a2e2b8bcbf2e06662bd13802db1e6a4 100644 (file)
@@ -25,7 +25,7 @@ update: ../../bin/$(PROG)
 ../../bin/$(PROG): $(PROG)
        cp $(PROG) ../../bin
 
-tests: test1 test2
+tests: test1 test2 fail_test
 
 root_tests:
 
@@ -55,6 +55,11 @@ test2:       $(PROG) map.in map-abc2.ref map-ghi2.ref map-uABC2.ref
        done
        rm -f map.in.db
 
+fail_test: $(PROG) aliases fail_test.in fail_test.ref
+       -sh fail_test.in > fail_test.tmp 2>&1 || exit 0
+       diff fail_test.ref fail_test.tmp
+       rm -f fail_test.tmp
+
 printfck: $(OBJS) $(PROG)
        rm -rf printfck
        mkdir printfck
diff --git a/postfix/src/postmap/aliases b/postfix/src/postmap/aliases
new file mode 100644 (file)
index 0000000..cce2b6b
--- /dev/null
@@ -0,0 +1 @@
+xx yy
diff --git a/postfix/src/postmap/fail_test.in b/postfix/src/postmap/fail_test.in
new file mode 100644 (file)
index 0000000..b62c3c5
--- /dev/null
@@ -0,0 +1,7 @@
+./postmap -q xx fail:aliases
+echo xx | ./postmap -q - fail:aliases
+./postmap -d xx fail:aliases
+echo xx | ./postmap -d - fail:aliases
+./postmap -s fail:aliases
+./postmap -i fail:aliases < aliases
+./postmap fail:aliases
diff --git a/postfix/src/postmap/fail_test.ref b/postfix/src/postmap/fail_test.ref
new file mode 100644 (file)
index 0000000..b9a92da
--- /dev/null
@@ -0,0 +1,7 @@
+postmap: fatal: fail:aliases: query error: Unknown error: 0
+postmap: fatal: fail:aliases: query error: Unknown error: 0
+postmap: fatal: fail:aliases: delete error: Unknown error: 0
+postmap: fatal: fail:aliases: delete error: Unknown error: 0
+postmap: fatal: fail:aliases: sequence error: Unknown error: 0
+postmap: fatal: fail:aliases: write error: Unknown error: 0
+postmap: fatal: fail:aliases: write error: Unknown error: 0
index 19bb02e5b9870209450c6c0046f19652442aead8..22718dd65c3d5bd22b025dce1c46e849164ef673 100644 (file)
 /* .IP \fBhash\fR
 /*     The output file is a hashed file, named \fIfile_name\fB.db\fR.
 /*     This is available on systems with support for \fBdb\fR databases.
+/* .IP \fBfail\fR
+/*     A table that reliably fails all requests. The lookup table
+/*     name is used for logging only. This table exists to simplify
+/*     Postfix error tests.
 /* .IP \fBsdbm\fR
 /*     The output consists of two files, named \fIfile_name\fB.pag\fR and
 /*     \fIfile_name\fB.dir\fR.
@@ -411,6 +415,9 @@ static void postmap(char *map_type, char *path_name, int postmap_flags,
         * Store the value under a case-insensitive key.
         */
        mkmap_append(mkmap, key, value);
+       if (mkmap->dict->error)
+           msg_fatal("%s:%s: write error: %m",
+                     mkmap->dict->type, mkmap->dict->name);
     }
 
     /*
@@ -458,6 +465,9 @@ static void postmap_body(void *ptr, int unused_rec_type,
            state->found = 1;
            break;
        }
+       if (dicts[n]->error)
+           msg_fatal("%s:%s: query error: %m",
+                     dicts[n]->type, dicts[n]->name);
     }
 }
 
@@ -535,6 +545,9 @@ static int postmap_queries(VSTREAM *in, char **maps, const int map_count,
                    found = 1;
                    break;
                }
+               if (dicts[n]->error)
+                   msg_fatal("%s:%s: query error: %m",
+                             dicts[n]->type, dicts[n]->name);
            }
        }
     } else {
@@ -616,6 +629,8 @@ static int postmap_query(const char *map_type, const char *map_name,
        }
        vstream_printf("%s\n", value);
     }
+    if (dict->error)
+       msg_fatal("%s:%s: query error: %m", dict->type, dict->name);
     vstream_fflush(VSTREAM_OUT);
     dict_close(dict);
     return (value != 0);
@@ -657,9 +672,14 @@ static int postmap_deletes(VSTREAM *in, char **maps, const int map_count,
     /*
      * Perform all requests.
      */
-    while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF)
-       for (n = 0; n < map_count; n++)
+    while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF) {
+       for (n = 0; n < map_count; n++) {
            found |= (dict_del(dicts[n], STR(keybuf)) == 0);
+           if (dicts[n]->error)
+               msg_fatal("%s:%s: delete error: %m",
+                         dicts[n]->type, dicts[n]->name);
+       }
+    }
 
     /*
      * Cleanup.
@@ -688,6 +708,8 @@ static int postmap_delete(const char *map_type, const char *map_name,
        open_flags = O_RDWR;
     dict = dict_open3(map_type, map_name, open_flags, dict_flags);
     status = dict_del(dict, key);
+    if (dict->error)
+       msg_fatal("%s:%s: delete error: %m", dict->type, dict->name);
     dict_close(dict);
     return (status == 0);
 }
@@ -719,6 +741,8 @@ static void postmap_seq(const char *map_type, const char *map_name,
        }
        vstream_printf("%s      %s\n", key, value);
     }
+    if (dict->error)
+       msg_fatal("%s:%s: sequence error: %m", dict->type, dict->name);
     vstream_fflush(VSTREAM_OUT);
     dict_close(dict);
 }
index fa7f996ba79fdfb19d0a5adc8fc2b5af05c232ee..a7a61837fa32b82a75fcc66c6b5a45c79ca559c8 100644 (file)
@@ -81,7 +81,6 @@ postscreen.o: ../../include/mail_server.h
 postscreen.o: ../../include/mail_version.h
 postscreen.o: ../../include/maps.h
 postscreen.o: ../../include/match_list.h
-postscreen.o: ../../include/match_ops.h
 postscreen.o: ../../include/msg.h
 postscreen.o: ../../include/myaddrinfo.h
 postscreen.o: ../../include/mymalloc.h
@@ -103,7 +102,6 @@ postscreen_dict.o: ../../include/events.h
 postscreen_dict.o: ../../include/htable.h
 postscreen_dict.o: ../../include/maps.h
 postscreen_dict.o: ../../include/match_list.h
-postscreen_dict.o: ../../include/match_ops.h
 postscreen_dict.o: ../../include/msg.h
 postscreen_dict.o: ../../include/server_acl.h
 postscreen_dict.o: ../../include/string_list.h
@@ -127,7 +125,6 @@ postscreen_dnsbl.o: ../../include/mail_params.h
 postscreen_dnsbl.o: ../../include/mail_proto.h
 postscreen_dnsbl.o: ../../include/maps.h
 postscreen_dnsbl.o: ../../include/match_list.h
-postscreen_dnsbl.o: ../../include/match_ops.h
 postscreen_dnsbl.o: ../../include/msg.h
 postscreen_dnsbl.o: ../../include/myaddrinfo.h
 postscreen_dnsbl.o: ../../include/mymalloc.h
@@ -151,7 +148,6 @@ postscreen_early.o: ../../include/htable.h
 postscreen_early.o: ../../include/mail_params.h
 postscreen_early.o: ../../include/maps.h
 postscreen_early.o: ../../include/match_list.h
-postscreen_early.o: ../../include/match_ops.h
 postscreen_early.o: ../../include/msg.h
 postscreen_early.o: ../../include/mymalloc.h
 postscreen_early.o: ../../include/server_acl.h
@@ -175,7 +171,6 @@ postscreen_expand.o: ../../include/mail_params.h
 postscreen_expand.o: ../../include/mail_proto.h
 postscreen_expand.o: ../../include/maps.h
 postscreen_expand.o: ../../include/match_list.h
-postscreen_expand.o: ../../include/match_ops.h
 postscreen_expand.o: ../../include/msg.h
 postscreen_expand.o: ../../include/server_acl.h
 postscreen_expand.o: ../../include/string_list.h
@@ -197,7 +192,6 @@ postscreen_misc.o: ../../include/iostuff.h
 postscreen_misc.o: ../../include/mail_params.h
 postscreen_misc.o: ../../include/maps.h
 postscreen_misc.o: ../../include/match_list.h
-postscreen_misc.o: ../../include/match_ops.h
 postscreen_misc.o: ../../include/msg.h
 postscreen_misc.o: ../../include/server_acl.h
 postscreen_misc.o: ../../include/string_list.h
@@ -220,7 +214,6 @@ postscreen_send.o: ../../include/mac_parse.h
 postscreen_send.o: ../../include/mail_params.h
 postscreen_send.o: ../../include/maps.h
 postscreen_send.o: ../../include/match_list.h
-postscreen_send.o: ../../include/match_ops.h
 postscreen_send.o: ../../include/msg.h
 postscreen_send.o: ../../include/server_acl.h
 postscreen_send.o: ../../include/smtp_reply_footer.h
@@ -246,7 +239,6 @@ postscreen_smtpd.o: ../../include/mail_params.h
 postscreen_smtpd.o: ../../include/mail_proto.h
 postscreen_smtpd.o: ../../include/maps.h
 postscreen_smtpd.o: ../../include/match_list.h
-postscreen_smtpd.o: ../../include/match_ops.h
 postscreen_smtpd.o: ../../include/msg.h
 postscreen_smtpd.o: ../../include/mymalloc.h
 postscreen_smtpd.o: ../../include/name_code.h
@@ -274,7 +266,6 @@ postscreen_starttls.o: ../../include/mail_params.h
 postscreen_starttls.o: ../../include/mail_proto.h
 postscreen_starttls.o: ../../include/maps.h
 postscreen_starttls.o: ../../include/match_list.h
-postscreen_starttls.o: ../../include/match_ops.h
 postscreen_starttls.o: ../../include/msg.h
 postscreen_starttls.o: ../../include/mymalloc.h
 postscreen_starttls.o: ../../include/name_code.h
@@ -302,7 +293,6 @@ postscreen_state.o: ../../include/mail_proto.h
 postscreen_state.o: ../../include/mail_server.h
 postscreen_state.o: ../../include/maps.h
 postscreen_state.o: ../../include/match_list.h
-postscreen_state.o: ../../include/match_ops.h
 postscreen_state.o: ../../include/msg.h
 postscreen_state.o: ../../include/mymalloc.h
 postscreen_state.o: ../../include/name_mask.h
@@ -323,7 +313,6 @@ postscreen_tests.o: ../../include/htable.h
 postscreen_tests.o: ../../include/mail_params.h
 postscreen_tests.o: ../../include/maps.h
 postscreen_tests.o: ../../include/match_list.h
-postscreen_tests.o: ../../include/match_ops.h
 postscreen_tests.o: ../../include/msg.h
 postscreen_tests.o: ../../include/server_acl.h
 postscreen_tests.o: ../../include/string_list.h
index 5c7c5cd075465977e161a2a9c342136b74212e8d..402d078fcbfb1fa21b1d06263efadb4ee6fc4792 100644 (file)
@@ -874,6 +874,8 @@ static void psc_smtpd_read_event(int event, char *context)
                         state->smtp_client_addr, state->smtp_client_port,
                         STR(state->cmd_buffer), cp);
                vstring_strcpy(state->cmd_buffer, cp);
+           } else if (psc_cmd_filter->error != 0) {
+               /* XXX log something, even if regexps don't soft-fail. */
            }
        }
 
index 024fadc7459a2889dc3c5f6ace459a9d0b313646..f0d4935df6a67113e83410764d68f669f92b7088 100644 (file)
@@ -339,7 +339,7 @@ static DICT *proxy_map_find(const char *map_type_name, int request_flags,
            msg_panic("proxy_map_find: dict_open null result");
        dict_register(STR(map_type_name_flags), dict);
     }
-    dict_errno = 0;
+    dict->error = 0;
     return (dict);
 }
 
@@ -352,6 +352,7 @@ static void proxymap_sequence_service(VSTREAM *client_stream)
     int     request_func;
     const char *reply_key;
     const char *reply_value;
+    int     dict_status;
     int     reply_status;
 
     /*
@@ -369,16 +370,19 @@ static void proxymap_sequence_service(VSTREAM *client_stream)
     } else if ((dict = proxy_map_find(STR(request_map), request_flags,
                                      &reply_status)) == 0) {
        reply_key = reply_value = "";
-    } else if (dict->flags = ((dict->flags & ~DICT_FLAG_RQST_MASK)
-                             | (request_flags & DICT_FLAG_RQST_MASK)),
-              dict_seq(dict, request_func, &reply_key, &reply_value) == 0) {
-       reply_status = PROXY_STAT_OK;
-    } else if (dict_errno == 0) {
-       reply_status = PROXY_STAT_NOKEY;
-       reply_key = reply_value = "";
     } else {
-       reply_status = PROXY_STAT_RETRY;
-       reply_key = reply_value = "";
+       dict->flags = ((dict->flags & ~DICT_FLAG_RQST_MASK)
+                      | (request_flags & DICT_FLAG_RQST_MASK));
+       dict_status = dict_seq(dict, request_func, &reply_key, &reply_value);
+       if (dict_status == 0) {
+           reply_status = PROXY_STAT_OK;
+       } else if (dict->error == 0) {
+           reply_status = PROXY_STAT_NOKEY;
+           reply_key = reply_value = "";
+       } else {
+           reply_status = PROXY_STAT_RETRY;
+           reply_key = reply_value = "";
+       }
     }
 
     /*
@@ -417,7 +421,7 @@ static void proxymap_lookup_service(VSTREAM *client_stream)
                              | (request_flags & DICT_FLAG_RQST_MASK)),
               (reply_value = dict_get(dict, STR(request_key))) != 0) {
        reply_status = PROXY_STAT_OK;
-    } else if (dict_errno == 0) {
+    } else if (dict->error == 0) {
        reply_status = PROXY_STAT_NOKEY;
        reply_value = "";
     } else {
@@ -440,6 +444,7 @@ static void proxymap_update_service(VSTREAM *client_stream)
 {
     int     request_flags;
     DICT   *dict;
+    int     dict_status;
     int     reply_status;
 
     /*
@@ -469,8 +474,14 @@ static void proxymap_update_service(VSTREAM *client_stream)
        dict->flags = ((dict->flags & ~DICT_FLAG_RQST_MASK)
                       | (request_flags & DICT_FLAG_RQST_MASK)
                       | DICT_FLAG_SYNC_UPDATE | DICT_FLAG_DUP_REPLACE);
-       dict_put(dict, STR(request_key), STR(request_value));
-       reply_status = (dict_errno ? PROXY_STAT_RETRY : PROXY_STAT_OK);
+       dict_status = dict_put(dict, STR(request_key), STR(request_value));
+       if (dict_status == 0) {
+           reply_status = PROXY_STAT_OK;
+       } else if (dict->error == 0) {
+           reply_status = PROXY_STAT_NOKEY;
+       } else {
+           reply_status = PROXY_STAT_RETRY;
+       }
     }
 
     /*
@@ -514,9 +525,13 @@ static void proxymap_delete_service(VSTREAM *client_stream)
                       | (request_flags & DICT_FLAG_RQST_MASK)
                       | DICT_FLAG_SYNC_UPDATE);
        dict_status = dict_del(dict, STR(request_key));
-       reply_status = (dict_status == 0 ? PROXY_STAT_OK :
-                       dict_status > 0 ? PROXY_STAT_NOKEY :
-                       PROXY_STAT_RETRY);
+       if (dict_status == 0) {
+           reply_status = PROXY_STAT_OK;
+       } else if (dict->error == 0) {
+           reply_status = PROXY_STAT_NOKEY;
+       } else {
+           reply_status = PROXY_STAT_RETRY;
+       }
     }
 
     /*
index c180709cf35532a9289e8de766bd384d03545fe1..e54679d48ee46c7a1397c11069d314c04c9d1a5d 100644 (file)
@@ -75,7 +75,6 @@ qmqpd.o: ../../include/mail_server.h
 qmqpd.o: ../../include/mail_stream.h
 qmqpd.o: ../../include/mail_version.h
 qmqpd.o: ../../include/match_list.h
-qmqpd.o: ../../include/match_ops.h
 qmqpd.o: ../../include/match_parent_style.h
 qmqpd.o: ../../include/msg.h
 qmqpd.o: ../../include/mymalloc.h
index e64bc6ebfbbd633551510f5ced9f4b6b3b472b56..559c2e0996d86945ab300a835ebb05c55c73fc8c 100644 (file)
@@ -689,7 +689,7 @@ static void qmqpd_proto(QMQPD_STATE *state)
         */
        if (namadr_list_match(qmqpd_clients, state->name, state->addr) != 0) {
            qmqpd_receive(state);
-       } else if (dict_errno == 0) {
+       } else if (qmqpd_clients->error == 0) {
            qmqpd_reply(state, DONT_LOG, QMQPD_STAT_HARD,
                        "Error: %s is not authorized to use this service",
                        state->namaddr);
index cc0aaf58e84b8940ba5a497d7e6a572398dc4025..0134a455dd917c91ff8af17843693af60597eeef 100644 (file)
@@ -107,7 +107,6 @@ smtp.o: ../../include/mail_server.h
 smtp.o: ../../include/mail_version.h
 smtp.o: ../../include/maps.h
 smtp.o: ../../include/match_list.h
-smtp.o: ../../include/match_ops.h
 smtp.o: ../../include/mime_state.h
 smtp.o: ../../include/msg.h
 smtp.o: ../../include/msg_stats.h
@@ -147,7 +146,6 @@ smtp_addr.o: ../../include/inet_proto.h
 smtp_addr.o: ../../include/mail_params.h
 smtp_addr.o: ../../include/maps.h
 smtp_addr.o: ../../include/match_list.h
-smtp_addr.o: ../../include/match_ops.h
 smtp_addr.o: ../../include/mime_state.h
 smtp_addr.o: ../../include/msg.h
 smtp_addr.o: ../../include/msg_stats.h
@@ -189,7 +187,6 @@ smtp_chat.o: ../../include/mail_error.h
 smtp_chat.o: ../../include/mail_params.h
 smtp_chat.o: ../../include/maps.h
 smtp_chat.o: ../../include/match_list.h
-smtp_chat.o: ../../include/match_ops.h
 smtp_chat.o: ../../include/mime_state.h
 smtp_chat.o: ../../include/msg.h
 smtp_chat.o: ../../include/msg_stats.h
@@ -232,7 +229,6 @@ smtp_connect.o: ../../include/mail_params.h
 smtp_connect.o: ../../include/mail_proto.h
 smtp_connect.o: ../../include/maps.h
 smtp_connect.o: ../../include/match_list.h
-smtp_connect.o: ../../include/match_ops.h
 smtp_connect.o: ../../include/mime_state.h
 smtp_connect.o: ../../include/msg.h
 smtp_connect.o: ../../include/msg_stats.h
@@ -272,7 +268,6 @@ smtp_map11.o: ../../include/htable.h
 smtp_map11.o: ../../include/mail_addr_map.h
 smtp_map11.o: ../../include/maps.h
 smtp_map11.o: ../../include/match_list.h
-smtp_map11.o: ../../include/match_ops.h
 smtp_map11.o: ../../include/mime_state.h
 smtp_map11.o: ../../include/msg.h
 smtp_map11.o: ../../include/msg_stats.h
@@ -317,7 +312,6 @@ smtp_proto.o: ../../include/mail_queue.h
 smtp_proto.o: ../../include/maps.h
 smtp_proto.o: ../../include/mark_corrupt.h
 smtp_proto.o: ../../include/match_list.h
-smtp_proto.o: ../../include/match_ops.h
 smtp_proto.o: ../../include/mime_state.h
 smtp_proto.o: ../../include/msg.h
 smtp_proto.o: ../../include/msg_stats.h
@@ -363,7 +357,6 @@ smtp_rcpt.o: ../../include/htable.h
 smtp_rcpt.o: ../../include/mail_params.h
 smtp_rcpt.o: ../../include/maps.h
 smtp_rcpt.o: ../../include/match_list.h
-smtp_rcpt.o: ../../include/match_ops.h
 smtp_rcpt.o: ../../include/mime_state.h
 smtp_rcpt.o: ../../include/msg.h
 smtp_rcpt.o: ../../include/msg_stats.h
@@ -396,7 +389,6 @@ smtp_reuse.o: ../../include/htable.h
 smtp_reuse.o: ../../include/mail_params.h
 smtp_reuse.o: ../../include/maps.h
 smtp_reuse.o: ../../include/match_list.h
-smtp_reuse.o: ../../include/match_ops.h
 smtp_reuse.o: ../../include/mime_state.h
 smtp_reuse.o: ../../include/msg.h
 smtp_reuse.o: ../../include/msg_stats.h
@@ -431,7 +423,6 @@ smtp_sasl_auth_cache.o: ../../include/header_opts.h
 smtp_sasl_auth_cache.o: ../../include/htable.h
 smtp_sasl_auth_cache.o: ../../include/maps.h
 smtp_sasl_auth_cache.o: ../../include/match_list.h
-smtp_sasl_auth_cache.o: ../../include/match_ops.h
 smtp_sasl_auth_cache.o: ../../include/mime_state.h
 smtp_sasl_auth_cache.o: ../../include/msg.h
 smtp_sasl_auth_cache.o: ../../include/msg_stats.h
@@ -465,7 +456,6 @@ smtp_sasl_glue.o: ../../include/mail_addr_find.h
 smtp_sasl_glue.o: ../../include/mail_params.h
 smtp_sasl_glue.o: ../../include/maps.h
 smtp_sasl_glue.o: ../../include/match_list.h
-smtp_sasl_glue.o: ../../include/match_ops.h
 smtp_sasl_glue.o: ../../include/mime_state.h
 smtp_sasl_glue.o: ../../include/msg.h
 smtp_sasl_glue.o: ../../include/msg_stats.h
@@ -501,7 +491,6 @@ smtp_sasl_proto.o: ../../include/htable.h
 smtp_sasl_proto.o: ../../include/mail_params.h
 smtp_sasl_proto.o: ../../include/maps.h
 smtp_sasl_proto.o: ../../include/match_list.h
-smtp_sasl_proto.o: ../../include/match_ops.h
 smtp_sasl_proto.o: ../../include/mime_state.h
 smtp_sasl_proto.o: ../../include/msg.h
 smtp_sasl_proto.o: ../../include/msg_stats.h
@@ -535,7 +524,6 @@ smtp_session.o: ../../include/htable.h
 smtp_session.o: ../../include/mail_params.h
 smtp_session.o: ../../include/maps.h
 smtp_session.o: ../../include/match_list.h
-smtp_session.o: ../../include/match_ops.h
 smtp_session.o: ../../include/mime_state.h
 smtp_session.o: ../../include/msg.h
 smtp_session.o: ../../include/msg_stats.h
@@ -569,7 +557,6 @@ smtp_state.o: ../../include/htable.h
 smtp_state.o: ../../include/mail_params.h
 smtp_state.o: ../../include/maps.h
 smtp_state.o: ../../include/match_list.h
-smtp_state.o: ../../include/match_ops.h
 smtp_state.o: ../../include/mime_state.h
 smtp_state.o: ../../include/msg.h
 smtp_state.o: ../../include/msg_stats.h
@@ -604,7 +591,6 @@ smtp_trouble.o: ../../include/htable.h
 smtp_trouble.o: ../../include/mail_error.h
 smtp_trouble.o: ../../include/maps.h
 smtp_trouble.o: ../../include/match_list.h
-smtp_trouble.o: ../../include/match_ops.h
 smtp_trouble.o: ../../include/mime_state.h
 smtp_trouble.o: ../../include/msg.h
 smtp_trouble.o: ../../include/msg_stats.h
@@ -636,7 +622,6 @@ smtp_unalias.o: ../../include/header_opts.h
 smtp_unalias.o: ../../include/htable.h
 smtp_unalias.o: ../../include/maps.h
 smtp_unalias.o: ../../include/match_list.h
-smtp_unalias.o: ../../include/match_ops.h
 smtp_unalias.o: ../../include/mime_state.h
 smtp_unalias.o: ../../include/msg.h
 smtp_unalias.o: ../../include/msg_stats.h
index 7cb1e11f38e80f9e02be90226fbc42feadd64fcc..213055e3d728cb2633f5ea6d189436df4d767b69 100644 (file)
@@ -300,6 +300,8 @@ SMTP_RESP *smtp_chat_resp(SMTP_SESSION *session)
                    smtp_chat_append(session, "Replaced-by: ", "");
                    smtp_chat_append(session, "     ", new_reply);
                }
+           } else if (smtp_chat_resp_filter->error != 0) {
+               /* XXX log something, even if regexps don't soft-fail. */
            }
        }
        if (chat_append_flag) {
index 23b2937e056e9f79581c5fe50daa18ac526ed237..8d7f75817a9a70a504d2ebd5e9e24584c8354e54 100644 (file)
@@ -91,7 +91,7 @@ int     smtp_map11_external(VSTRING *addr, MAPS *maps, int propagate)
        argv_free(new_addr);
        return (1);
     } else {
-       if (dict_errno != 0)
+       if (maps->error != 0)
            msg_fatal("%s map lookup problem for %s", maps->title, STR(addr));
        if (msg_verbose)
            msg_info("%s: %s not found", myname, STR(addr));
index 682c4fba3abda2ccea887ecae0c5a28f8c3fccfa..4f0d7e89af5adfae5d09cdc589f8acbb9cc2b900 100644 (file)
@@ -239,7 +239,7 @@ int     smtp_sasl_auth_cache_find(SMTP_SASL_AUTH_CACHE *auth_cache,
        if ((valid = smtp_sasl_auth_cache_valid_value(auth_cache, entry,
                                                session->sasl_passwd)) == 0)
            /* Remove expired, password changed, or malformed cache entry. */
-           if (dict_del(auth_cache->dict, key) == 0)
+           if (dict_del(auth_cache->dict, key) != 0)
                msg_warn("SASL auth failure map %s: entry not deleted: %s",
                         auth_cache->dict->name, key);
     myfree(key);
index f053b1679d23afa4460d7d5ac1bbf1dc768d6b25..a311c77ec48fee9c338be61e4f51aabff6003070 100644 (file)
@@ -177,7 +177,6 @@ smtpd.o: ../../include/mail_stream.h
 smtpd.o: ../../include/mail_version.h
 smtpd.o: ../../include/maps.h
 smtpd.o: ../../include/match_list.h
-smtpd.o: ../../include/match_ops.h
 smtpd.o: ../../include/milter.h
 smtpd.o: ../../include/msg.h
 smtpd.o: ../../include/myaddrinfo.h
@@ -285,7 +284,6 @@ smtpd_check.o: ../../include/mail_proto.h
 smtpd_check.o: ../../include/mail_stream.h
 smtpd_check.o: ../../include/maps.h
 smtpd_check.o: ../../include/match_list.h
-smtpd_check.o: ../../include/match_ops.h
 smtpd_check.o: ../../include/match_parent_style.h
 smtpd_check.o: ../../include/milter.h
 smtpd_check.o: ../../include/msg.h
index 6e90bf10dbbc8419a1176cf6a236a99d5198a250..a489981fd0aa318fdca5d3a45d52fd4d49e38144 100644 (file)
@@ -4649,6 +4649,8 @@ static void smtpd_proto(SMTPD_STATE *state)
                    msg_info("%s: replacing command \"%.100s\" with \"%.100s\"",
                             state->namaddr, STR(state->buffer), cp);
                    vstring_strcpy(state->buffer, cp);
+               } else if (smtpd_cmd_filter->error != 0) {
+                   /* XXX log something, even if regexps don't soft-fail. */
                }
            }
            if ((argc = smtpd_token(vstring_str(state->buffer), &argv)) == 0) {
index 4461cb384856ba3ecabd998e6087122fee105fc1..51616b616b6ee5e3e196b584c6ad3bfc415e9dff 100644 (file)
 static jmp_buf smtpd_check_buf;
 
  /*
-  * Results of restrictions.
+  * Results of restrictions. Errors are negative; see dict.h.
   */
-#define SMTPD_CHECK_ERROR      (-1)    /* server error */
 #define SMTPD_CHECK_DUNNO      0       /* indifferent */
 #define SMTPD_CHECK_OK         1       /* explicitly permit */
 #define SMTPD_CHECK_REJECT     2       /* explicitly reject */
@@ -922,10 +921,9 @@ static const char *check_mail_addr_find(SMTPD_STATE *state,
 {
     const char *result;
 
-    dict_errno = 0;
-    if ((result = mail_addr_find(maps, key, ext)) != 0 || dict_errno == 0)
+    if ((result = mail_addr_find(maps, key, ext)) != 0 || maps->error == 0)
        return (result);
-    if (dict_errno == DICT_ERR_RETRY)
+    if (maps->error == DICT_ERR_RETRY)
        reject_dict_retry(state, reply_name);
     else
        reject_server_error(state);
@@ -1010,10 +1008,10 @@ static int permit_mynetworks(SMTPD_STATE *state)
 
     if (namadr_list_match(mynetworks, state->name, state->addr))
        return (SMTPD_CHECK_OK);
-    else if (dict_errno == 0)
+    else if (mynetworks->error == 0)
        return (SMTPD_CHECK_DUNNO);
     else
-       return (SMTPD_CHECK_ERROR);
+       return (mynetworks->error);
 }
 
 /* dup_if_truncate - save hostname and truncate if it ends in dot */
@@ -1242,8 +1240,6 @@ static int permit_tls_clientcerts(SMTPD_STATE *state, int permit_all_certs)
 #ifdef USE_TLS
     const char *found = 0;
 
-    dict_errno = 0;
-
     if (!state->tls_context)
        return SMTPD_CHECK_DUNNO;
 
@@ -1264,25 +1260,23 @@ static int permit_tls_clientcerts(SMTPD_STATE *state, int permit_all_certs)
        prints[0] = state->tls_context->peer_fingerprint;
        prints[1] = state->tls_context->peer_pkey_fprint;
 
-       /* After lookup error, leave dict_errno at non-zero value. */
+       /* After lookup error, leave relay_ccerts->error at non-zero value. */
        for (i = 0; i < 2; ++i) {
            found = maps_find(relay_ccerts, prints[i], DICT_FLAG_NONE);
            if (found != 0) {
                if (msg_verbose)
                    msg_info("Relaying allowed for certified client: %s", found);
                return (SMTPD_CHECK_OK);
-           } else if (dict_errno != 0) {
+           } else if (relay_ccerts->error != 0) {
                msg_warn("relay_clientcerts: lookup error for fingerprint '%s', "
                         "pkey fingerprint %s", prints[0], prints[1]);
-               return (SMTPD_CHECK_ERROR);
+               return (relay_ccerts->error);
            }
        }
        if (msg_verbose)
            msg_info("relay_clientcerts: No match for fingerprint '%s', "
                     "pkey fingerprint %s", prints[0], prints[1]);
     }
-#else
-    dict_errno = 0;
 #endif
     return (SMTPD_CHECK_DUNNO);
 }
@@ -1462,7 +1456,7 @@ static int all_auth_mx_addr(SMTPD_STATE *state, char *host,
            msg_info("%s: checking: %s", myname, hostaddr.buf);
 
        if (!namadr_list_match(perm_mx_networks, host, hostaddr.buf)) {
-           if (dict_errno == 0) {
+           if (perm_mx_networks->error == 0) {
 
                /*
                 * Reject: at least one IP address is not listed in
@@ -1556,7 +1550,7 @@ static int i_am_mx(SMTPD_STATE *state, DNS_RR *mx_list,
     for (mx = mx_list; mx != 0; mx = mx->next) {
        if (msg_verbose)
            msg_info("%s: resolve hostname: %s", myname, (char *) mx->data);
-       if (resolve_local((char *) mx->data))
+       if (resolve_local((char *) mx->data) > 0)
            return (YUP);
        /* if no match or error, match interface addresses instead. */
     }
@@ -2367,7 +2361,7 @@ static int check_access(SMTPD_STATE *state, const char *table, const char *name,
            CHK_ACCESS_RETURN(check_table_result(state, table, value, name,
                                                 reply_name, reply_class,
                                                 def_acl), FOUND);
-       if (dict_errno != 0) {
+       if (dict->error != 0) {
            msg_warn("%s: table lookup problem", table);
            value = "451 4.3.5 Server configuration error";
            CHK_ACCESS_RETURN(check_table_result(state, table, value, name,
@@ -2418,7 +2412,7 @@ static int check_domain_access(SMTPD_STATE *state, const char *table,
                CHK_DOMAIN_RETURN(check_table_result(state, table, value,
                                            domain, reply_name, reply_class,
                                                     def_acl), FOUND);
-           if (dict_errno != 0) {
+           if (dict->error != 0) {
                msg_warn("%s: table lookup problem", table);
                value = "451 4.3.5 Server configuration error";
                CHK_DOMAIN_RETURN(check_table_result(state, table, value,
@@ -2482,7 +2476,7 @@ static int check_addr_access(SMTPD_STATE *state, const char *table,
                CHK_ADDR_RETURN(check_table_result(state, table, value, address,
                                                   reply_name, reply_class,
                                                   def_acl), FOUND);
-           if (dict_errno != 0) {
+           if (dict->error != 0) {
                msg_warn("%s: table lookup problem", table);
                value = "451 4.3.5 Server configuration error";
                CHK_ADDR_RETURN(check_table_result(state, table, value, address,
@@ -4068,8 +4062,8 @@ static int generic_checks(SMTPD_STATE *state, ARGV *restrictions,
        if (msg_verbose)
            msg_info("%s: name=%s status=%d", myname, name, status);
 
-       if (status == SMTPD_CHECK_ERROR) {
-           if (dict_errno == DICT_ERR_RETRY)
+       if (status < 0) {
+           if (status == DICT_ERR_RETRY)
                reject_dict_retry(state, reply_name);
            else
                reject_server_error(state);
@@ -4143,12 +4137,11 @@ char   *smtpd_check_rewrite(SMTPD_STATE *state)
        } else if (is_map_command(state, name, CHECK_ADDR_MAP, &cpp)) {
            if ((dict = dict_handle(*cpp)) == 0)
                msg_panic("%s: dictionary not found: %s", myname, *cpp);
-           dict_errno = 0;
            if (dict_get(dict, state->addr) != 0)
                status = SMTPD_CHECK_OK;
-           else if (dict_errno != 0) {
+           else if (dict->error != 0) {
                msg_warn("%s: %s: lookup error", VAR_LOC_RWR_CLIENTS, *cpp);
-               status = SMTPD_CHECK_ERROR;
+               status = dict->error;
            }
        } else if (strcasecmp(name, PERMIT_SASL_AUTH) == 0) {
 #ifdef USE_SASL_AUTH
@@ -4165,8 +4158,8 @@ char   *smtpd_check_rewrite(SMTPD_STATE *state)
                     VAR_LOC_RWR_CLIENTS, name);
            continue;
        }
-       if (status == SMTPD_CHECK_ERROR) {
-           if (dict_errno == DICT_ERR_RETRY) {
+       if (status < 0) {
+           if (status == DICT_ERR_RETRY) {
                state->error_mask |= MAIL_ERROR_RESOURCE;
                log_whatsup(state, "reject",
                            "451 4.3.0 Temporary lookup error");
@@ -5226,6 +5219,7 @@ void    resolve_clnt(const char *class, const char *unused_sender, const char *a
                             RESOLVE_REPLY *reply)
 {
     const char *domain;
+    int     rc;
 
     if (addr == CONST_STR(reply->recipient))
        msg_panic("resolve_clnt_query: result clobbers input");
@@ -5234,29 +5228,29 @@ void    resolve_clnt(const char *class, const char *unused_sender, const char *a
     if ((domain = strrchr(addr, '@')) == 0)
        msg_fatal("%s: unqualified address", addr);
     domain += 1;
-    if (resolve_local(domain)) {
+    if ((rc = resolve_local(domain)) > 0) {
        reply->flags = RESOLVE_CLASS_LOCAL;
        vstring_strcpy(reply->transport, MAIL_SERVICE_LOCAL);
        vstring_strcpy(reply->nexthop, domain);
-    } else if (dict_errno) {
+    } else if (rc < 0) {
        reply->flags = RESOLVE_FLAG_FAIL;
     } else if (string_list_match(virt_alias_doms, domain)) {
        reply->flags = RESOLVE_CLASS_ALIAS;
        vstring_strcpy(reply->transport, MAIL_SERVICE_ERROR);
        vstring_strcpy(reply->nexthop, "user unknown");
-    } else if (dict_errno) {
+    } else if (virt_alias_doms->error) {
        reply->flags = RESOLVE_FLAG_FAIL;
     } else if (string_list_match(virt_mailbox_doms, domain)) {
        reply->flags = RESOLVE_CLASS_VIRTUAL;
        vstring_strcpy(reply->transport, MAIL_SERVICE_VIRTUAL);
        vstring_strcpy(reply->nexthop, domain);
-    } else if (dict_errno) {
+    } else if (virt_mailbox_doms->error) {
        reply->flags = RESOLVE_FLAG_FAIL;
     } else if (domain_list_match(relay_domains, domain)) {
        reply->flags = RESOLVE_CLASS_RELAY;
        vstring_strcpy(reply->transport, MAIL_SERVICE_RELAY);
        vstring_strcpy(reply->nexthop, domain);
-    } else if (dict_errno) {
+    } else if (relay_domains->error) {
        reply->flags = RESOLVE_FLAG_FAIL;
     } else {
        reply->flags = RESOLVE_CLASS_DEFAULT;
index 6f4e24e8f95d61f983af482f4b02e5223b9ddc4b..199585680c5ae956858ef38b26f9ba36828eb600 100644 (file)
@@ -74,7 +74,6 @@ resolve.o: ../../include/mail_params.h
 resolve.o: ../../include/mail_proto.h
 resolve.o: ../../include/maps.h
 resolve.o: ../../include/match_list.h
-resolve.o: ../../include/match_ops.h
 resolve.o: ../../include/match_parent_style.h
 resolve.o: ../../include/msg.h
 resolve.o: ../../include/mymalloc.h
@@ -124,7 +123,7 @@ transport.o: ../../include/iostuff.h
 transport.o: ../../include/mail_params.h
 transport.o: ../../include/mail_proto.h
 transport.o: ../../include/maps.h
-transport.o: ../../include/match_ops.h
+transport.o: ../../include/match_list.h
 transport.o: ../../include/match_parent_style.h
 transport.o: ../../include/msg.h
 transport.o: ../../include/mymalloc.h
index 6b49b3dbd8e10840f3fc27d9a714dcf6bc45cab0..c237b312f23d70ce40c7f12888768890a80cf46f 100644 (file)
@@ -155,6 +155,7 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr,
     const char *relay;
     const char *xport;
     const char *sender_key;
+    int     rc;
 
     *flags = 0;
     vstring_strcpy(channel, "CHANNEL NOT UPDATED");
@@ -259,8 +260,8 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr,
         * requestor.
         */
        if ((domain = tok822_rfind_type(tree->tail, '@')) != 0) {
-           if (domain->next && RESOLVE_LOCAL(domain->next) == 0) {
-               if (dict_errno != 0) {
+           if (domain->next && (rc = RESOLVE_LOCAL(domain->next)) <= 0) {
+               if (rc < 0) {
                    *flags |= RESOLVE_FLAG_FAIL;
                    FREE_MEMORY_AND_RETURN;
                }
@@ -377,9 +378,9 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr,
            vstring_insert(nextrcpt, rcpt_domain - STR(nextrcpt), "[", 1);
            vstring_strcat(nextrcpt, "]");
            rcpt_domain = strrchr(STR(nextrcpt), '@') + 1;
-           if (resolve_local(rcpt_domain))     /* XXX */
+           if ((rc = resolve_local(rcpt_domain)) > 0)  /* XXX */
                domain = 0;
-           else if (dict_errno != 0) {
+           else if (rc < 0) {
                *flags |= RESOLVE_FLAG_FAIL;
                FREE_MEMORY_AND_RETURN;
            }
@@ -427,7 +428,6 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr,
      */
 #define STREQ(x,y) (strcmp((x), (y)) == 0)
 
-    dict_errno = 0;
     if (domain != 0) {
 
        /*
@@ -457,7 +457,7 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr,
                            var_show_unk_rcpt_table ?
                            " in virtual alias table" : "");
            *flags |= RESOLVE_CLASS_ALIAS;
-       } else if (dict_errno != 0) {
+       } else if (virt_alias_doms && virt_alias_doms->error != 0) {
            msg_warn("%s lookup failure", VAR_VIRT_ALIAS_DOMS);
            *flags |= RESOLVE_FLAG_FAIL;
            FREE_MEMORY_AND_RETURN;
@@ -479,7 +479,7 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr,
            vstring_strcpy(nexthop, rcpt_domain);
            blame = rp->virt_transport_name;
            *flags |= RESOLVE_CLASS_VIRTUAL;
-       } else if (dict_errno != 0) {
+       } else if (virt_mailbox_doms && virt_mailbox_doms->error != 0) {
            msg_warn("%s lookup failure", VAR_VIRT_MAILBOX_DOMS);
            *flags |= RESOLVE_FLAG_FAIL;
            FREE_MEMORY_AND_RETURN;
@@ -493,7 +493,7 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr,
                vstring_strcpy(channel, RES_PARAM_VALUE(rp->relay_transport));
                blame = rp->relay_transport_name;
                *flags |= RESOLVE_CLASS_RELAY;
-           } else if (dict_errno != 0) {
+           } else if (relay_domains && relay_domains->error != 0) {
                msg_warn("%s lookup failure", VAR_RELAY_DOMAINS);
                *flags |= RESOLVE_FLAG_FAIL;
                FREE_MEMORY_AND_RETURN;
@@ -516,7 +516,8 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr,
                    vstring_strcpy(channel, strcasecmp(xport, "DUNNO") == 0 ?
                                RES_PARAM_VALUE(rp->def_transport) : xport);
                    blame = rp->snd_def_xp_maps_name;
-               } else if (dict_errno != 0) {
+               } else if (rp->snd_def_xp_info
+                          && rp->snd_def_xp_info->error != 0) {
                    msg_warn("%s lookup failure", rp->snd_def_xp_maps_name);
                    *flags |= RESOLVE_FLAG_FAIL;
                    FREE_MEMORY_AND_RETURN;
@@ -543,7 +544,8 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr,
                }
                vstring_strcpy(nexthop, strcasecmp(relay, "DUNNO") == 0 ?
                               rcpt_domain : relay);
-           } else if (dict_errno != 0) {
+           } else if (rp->snd_relay_info
+                      && rp->snd_relay_info->error != 0) {
                msg_warn("%s lookup failure", rp->snd_relay_maps_name);
                *flags |= RESOLVE_FLAG_FAIL;
                FREE_MEMORY_AND_RETURN;
@@ -632,7 +634,7 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr,
     if (rp->transport_info && !(*flags & RESOLVE_CLASS_ALIAS)) {
        if (transport_lookup(rp->transport_info, STR(nextrcpt),
                             rcpt_domain, channel, nexthop) == 0
-           && dict_errno != 0) {
+           && rp->transport_info->transport_path->error != 0) {
            msg_warn("%s lookup failure", rp->transport_maps_name);
            *flags |= RESOLVE_FLAG_FAIL;
            FREE_MEMORY_AND_RETURN;
@@ -658,7 +660,7 @@ static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr,
            vstring_strcpy(channel, MAIL_SERVICE_ERROR);
            /* 5.1.6 is the closest match, but not perfect. */
            vstring_sprintf(nexthop, "5.1.6 User has moved to %s", newloc);
-       } else if (dict_errno != 0) {
+       } else if (relocated_maps->error != 0) {
            msg_warn("%s lookup failure", VAR_RELOCATED_MAPS);
            *flags |= RESOLVE_FLAG_FAIL;
            FREE_MEMORY_AND_RETURN;
index 4b3c98bc704ebd20aa6dea4b0ee3afffcdf78846..29720541c82bd4683ceddb9545edd1ab3ff58136 100644 (file)
@@ -169,11 +169,6 @@ static int find_transport_entry(TRANSPORT_INFO *tp, const char *key,
     const char *host;
     const char *value;
 
-    /*
-     * Reset previous error history.
-     */
-    dict_errno = 0;
-
 #define FOUND          1
 #define NOTFOUND       0
 
@@ -241,7 +236,7 @@ static void transport_wildcard_init(TRANSPORT_INFO *tp)
            msg_info("wildcard_{chan:hop}={%s:%s}",
                     vstring_str(channel), vstring_str(nexthop));
     } else {
-       tp->wildcard_errno = dict_errno;
+       tp->wildcard_errno = tp->transport_path->error;
        vstring_free(channel);
        vstring_free(nexthop);
        tp->wildcard_channel = 0;
@@ -282,7 +277,7 @@ int     transport_lookup(TRANSPORT_INFO *tp, const char *addr,
 
     if (find_transport_entry(tp, addr, rcpt_domain, FULL, channel, nexthop))
        return (FOUND);
-    if (dict_errno != 0)
+    if (tp->transport_path->error != 0)
        return (NOTFOUND);
 
     /*
@@ -298,7 +293,7 @@ int     transport_lookup(TRANSPORT_INFO *tp, const char *addr,
        myfree(stripped_addr);
        if (found)
            return (FOUND);
-       if (dict_errno != 0)
+       if (tp->transport_path->error != 0)
            return (NOTFOUND);
     }
 
@@ -321,7 +316,7 @@ int     transport_lookup(TRANSPORT_INFO *tp, const char *addr,
     for (name = ratsign + 1; *name != 0; name = next) {
        if (find_transport_entry(tp, name, rcpt_domain, PARTIAL, channel, nexthop))
            return (FOUND);
-       if (dict_errno != 0)
+       if (tp->transport_path->error != 0)
            return (NOTFOUND);
        if ((next = strchr(name + 1, '.')) == 0)
            break;
@@ -335,7 +330,7 @@ int     transport_lookup(TRANSPORT_INFO *tp, const char *addr,
     if (tp->wildcard_errno || event_time() > tp->expire)
        transport_wildcard_init(tp);
     if (tp->wildcard_errno) {
-       dict_errno = tp->wildcard_errno;
+       tp->transport_path->error = tp->wildcard_errno;
        return (NOTFOUND);
     } else if (tp->wildcard_channel) {
        update_entry(STR(tp->wildcard_channel), STR(tp->wildcard_nexthop),
index 3687fe12db699fc94868044077b1c9e54be761a5..368a1cea89fd107d2133954215859256636a1642 100644 (file)
@@ -34,7 +34,7 @@ SRCS  = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \
        unix_pass_listen.c unix_pass_trigger.c edit_file.c inet_windowsize.c \
        unix_pass_fd_fix.c dict_cache.c valid_utf_8.c dict_thash.c \
        ip_match.c nbbio.c stream_pass_connect.c base32_code.c dict_test.c \
-       dict_fail.c
+       dict_fail.c msg_rate_delay.c
 OBJS   = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
        attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
        attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
@@ -70,7 +70,7 @@ OBJS  = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
        unix_pass_listen.o unix_pass_trigger.o edit_file.o inet_windowsize.o \
        unix_pass_fd_fix.o dict_cache.o valid_utf_8.o dict_thash.o \
        ip_match.o nbbio.o stream_pass_connect.o base32_code.o dict_test.o \
-       dict_fail.o
+       dict_fail.o msg_rate_delay.o
 HDRS   = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
        chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \
        dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \
@@ -80,7 +80,7 @@ HDRS  = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
        get_domainname.h get_hostname.h hex_code.h hex_quote.h host_port.h \
        htable.h inet_addr_host.h inet_addr_list.h inet_addr_local.h \
        inet_proto.h iostuff.h line_wrap.h listen.h lstat_as.h mac_expand.h \
-       mac_parse.h make_dirs.h mask_addr.h match_list.h match_ops.h msg.h \
+       mac_parse.h make_dirs.h mask_addr.h match_list.h msg.h \
        msg_output.h msg_syslog.h msg_vstream.h mvect.h myaddrinfo.h myflock.h \
        mymalloc.h myrand.h name_code.h name_mask.h netstring.h nvtable.h \
        open_as.h open_lock.h percentm.h posix_signals.h readlline.h ring.h \
@@ -109,7 +109,7 @@ TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \
        attr_scan0 host_port attr_scan_plain attr_print_plain htable \
        unix_recv_fd unix_send_fd stream_recv_fd stream_send_fd hex_code \
        myaddrinfo myaddrinfo4 inet_proto sane_basename format_tv \
-       valid_utf_8 ip_match base32_code
+       valid_utf_8 ip_match base32_code msg_rate_delay
 
 LIB_DIR        = ../../lib
 INC_DIR        = ../../include
@@ -434,6 +434,11 @@ base32_code: $(LIB)
        $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
        mv junk $@.o
 
+msg_rate_delay: $(LIB)
+       mv $@.o junk
+       $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
+       mv junk $@.o
+
 tests: valid_hostname_test mac_expand_test dict_test unescape_test \
        hex_quote_test ctable_test inet_addr_list_test base64_code_test \
        attr_scan64_test attr_scan0_test dict_pcre_test host_port_test \
@@ -1352,7 +1357,6 @@ match_list.o: argv.h
 match_list.o: dict.h
 match_list.o: match_list.c
 match_list.o: match_list.h
-match_list.o: match_ops.h
 match_list.o: msg.h
 match_list.o: mymalloc.h
 match_list.o: stringops.h
@@ -1364,8 +1368,8 @@ match_list.o: vstring_vstream.h
 match_ops.o: argv.h
 match_ops.o: cidr_match.h
 match_ops.o: dict.h
+match_ops.o: match_list.h
 match_ops.o: match_ops.c
-match_ops.o: match_ops.h
 match_ops.o: msg.h
 match_ops.o: myaddrinfo.h
 match_ops.o: mymalloc.h
@@ -1389,6 +1393,12 @@ msg_output.o: sys_defs.h
 msg_output.o: vbuf.h
 msg_output.o: vstream.h
 msg_output.o: vstring.h
+msg_rate_delay.o: events.h
+msg_rate_delay.o: msg.h
+msg_rate_delay.o: msg_rate_delay.c
+msg_rate_delay.o: sys_defs.h
+msg_rate_delay.o: vbuf.h
+msg_rate_delay.o: vstring.h
 msg_syslog.o: msg.h
 msg_syslog.o: msg_output.h
 msg_syslog.o: msg_syslog.c
index 30a51b9f22cde663fc683caa69ffaa53bbd5e422..baeff9d2043074c1f1ef00e3a4fc778c2c3aa608 100644 (file)
@@ -6,9 +6,6 @@
 /* SYNOPSIS
 /*     #include <dict.h>
 /*
-/*     extern int dict_unknown_allowed;
-/*     extern int dict_errno;
-/*
 /*     void    dict_register(dict_name, dict_info)
 /*     const char *dict_name;
 /*     DICT    *dict_info;
@@ -19,7 +16,7 @@
 /*     void    dict_unregister(dict_name)
 /*     const char *dict_name;
 /*
-/*     void    dict_update(dict_name, member, value)
+/*     int     dict_update(dict_name, member, value)
 /*     const char *dict_name;
 /*     const char *member;
 /*     const char *value;
@@ -47,6 +44,9 @@
 /*     void    (*action)(dict_name, dict_handle, context)
 /*     char    *context;
 /*
+/*     int     dict_error(dict_name)
+/*     const char *dict_name;
+/*
 /*     const char *dict_changed_name()
 /* AUXILIARY FUNCTIONS
 /*     void    dict_load_file(dict_name, path)
 /*     value of \fIname\fR. The forms $(\fIname\fR) and ${\fIname\fR} are
 /*     also supported.
 /* .IP "unknown names"
-/*     References to unknown dictionary or dictionary member names either
-/*     default to an empty dictionary or null pointer value, or cause a
-/*     run-time error. The behavior is controlled by the global
-/*     \fIdict_unknown_allowed\fR boolean variable.
+/*     An update request for an unknown dictionary name will trigger
+/*     the instantiation of an in-memory dictionary with that name.
+/*     A lookup request (including delete and sequence) for an
+/*     unknown dictionary will result in a "not found" and "no
+/*     error" result.
 /* .PP
 /*     dict_register() adds a new dictionary, including access methods,
 /*     to the list of known dictionaries, or increments the reference
@@ -97,7 +98,8 @@
 /*
 /*     dict_update() updates the value of the named dictionary member.
 /*     The dictionary member and the named dictionary are instantiated
-/*     on the fly.
+/*     on the fly.  The result value is zero (DICT_STAT_SUCCESS)
+/*     when the update was made.
 /*
 /*     dict_lookup() returns the value of the named member (i.e. without
 /*     expanding macros in the member value).  The \fIdict_name\fR argument
 /*     modified, or if the result is to survive multiple dict_lookup() calls.
 /*
 /*     dict_delete() removes the named member from the named dictionary.
-/*     The result value is zero when the member was found, > 0 if
-/*     it was not found, and < 0 in case of error (a database may
-/*     not return after error).
+/*     The result value is zero (DICT_STAT_SUCCESS) when the member
+/*     was found.
 /*
 /*     dict_sequence() steps through the named dictionary and returns
 /*     keys and values in some implementation-defined order. The func
 /*     entry or DICT_SEQ_FUN_NEXT to select the next entry. The result
 /*     is owned by the underlying dictionary method. Make a copy if the
 /*     result is to be modified, or if the result is to survive multiple
-/*     dict_sequence() calls. The result value is zero when a member
-/*     was found.
+/*     dict_sequence() calls. The result value is zero (DICT_STAT_SUCCESS)
+/*     when a member was found.
 /*
 /*     dict_eval() expands macro references in the specified string.
 /*     The result is owned by the dictionary manager. Make a copy if the
 /*     htable(3)
 /* BUGS
 /* DIAGNOSTICS
-/*     Fatal errors: out of memory, reference to unknown name,
-/*     malformed macro name.
+/*     Fatal errors: out of memory, malformed macro name.
 /*
-/*     The lookup routines may set the \fIdict_errno\fR variable when
-/*     they were unable to find the requested result. The lookup
-/*     routines must reset \fIdict_errno\fR before each lookup operation.
-/*     \fIdict_errno\fR can have the following values:
-/* .IP DICT_ERR_RETRY
+/*     The lookup routine returns non-null when the request is
+/*     satisfied. The update, delete and sequence routines return
+/*     zero (DICT_STAT_SUCCESS) when the request is satisfied.
+/*     The dict_error() function returns non-zero only when the
+/*     last operation was not satisfied due to a dictionary access
+/*     error. The result can have the following values:
+/* .IP DICT_ERR_NONE(zero)
+/*     There was no dictionary access error. For example, the
+/*     request was satisfied, the requested information did not
+/*     exist in the dictionary, or the information already existed
+/*     when it should not exist (collision).
+/* .IP DICT_ERR_RETRY(<0)
 /*     The dictionary was temporarily unavailable. This can happen
 /*     with network-based services.
+/* .IP DICT_ERR_CONFIG(<0)
+/*     The dictionary was unavailable due to a configuration error.
+/* .PP
+/*     Generally, a program is expected to test the function result
+/*     value for "success" first. If the operation was not successful,
+/*     a program is expected to test for a non-zero dict->error
+/*     status to distinguish between a data notfound/collision
+/*     condition or a dictionary access error.
 /* LICENSE
 /* .ad
 /* .fi
 #include "dict.h"
 #include "dict_ht.h"
 
- /*
-  * By default, use a sane default for an unknown name.
-  */
-int     dict_unknown_allowed = 1;
-int     dict_errno = 0;
-
 static HTABLE *dict_table;
 
  /*
@@ -222,6 +231,27 @@ typedef struct {
 #define dict_node(dict) \
        (dict_table ? (DICT_NODE *) htable_find(dict_table, dict) : 0)
 
+/* Find a dictionary handle by name for lookup purposes. */
+
+#define DICT_FIND_FOR_LOOKUP(dict, dict_name) do { \
+    DICT_NODE *node; \
+    if ((node = dict_node(dict_name)) != 0) \
+       dict = node->dict; \
+    else \
+       dict = 0; \
+} while (0)
+
+/* Find a dictionary handle by name for update purposes. */
+
+#define DICT_FIND_FOR_UPDATE(dict, dict_name) do { \
+    DICT_NODE *node; \
+    if ((node = dict_node(dict_name)) == 0) { \
+       dict = dict_ht_open(dict_name, O_CREAT | O_RDWR, 0); \
+       dict_register(dict_name, dict); \
+    } else \
+       dict = node->dict; \
+} while (0)
+
 #define STR(x) vstring_str(x)
 
 /* dict_register - make association with dictionary */
@@ -283,22 +313,15 @@ void    dict_unregister(const char *dict_name)
 
 /* dict_update - replace or add dictionary entry */
 
-void    dict_update(const char *dict_name, const char *member, const char *value)
+int     dict_update(const char *dict_name, const char *member, const char *value)
 {
     const char *myname = "dict_update";
-    DICT_NODE *node;
     DICT   *dict;
 
-    if ((node = dict_node(dict_name)) == 0) {
-       if (dict_unknown_allowed == 0)
-           msg_fatal("%s: unknown dictionary: %s", myname, dict_name);
-       dict = dict_ht_open(dict_name, O_CREAT | O_RDWR, 0);
-       dict_register(dict_name, dict);
-    } else
-       dict = node->dict;
+    DICT_FIND_FOR_UPDATE(dict, dict_name);
     if (msg_verbose > 1)
        msg_info("%s: %s = %s", myname, member, value);
-    dict->update(dict, member, value);
+    return (dict->update(dict, member, value));
 }
 
 /* dict_lookup - look up dictionary entry */
@@ -306,22 +329,21 @@ void    dict_update(const char *dict_name, const char *member, const char *value
 const char *dict_lookup(const char *dict_name, const char *member)
 {
     const char *myname = "dict_lookup";
-    DICT_NODE *node;
     DICT   *dict;
-    const char *ret = 0;
+    const char *ret;
 
-    if ((node = dict_node(dict_name)) == 0) {
-       if (dict_unknown_allowed == 0)
-           msg_fatal("%s: unknown dictionary: %s", myname, dict_name);
-    } else {
-       dict = node->dict;
+    DICT_FIND_FOR_LOOKUP(dict, dict_name);
+    if (dict != 0) {
        ret = dict->lookup(dict, member);
-       if (ret == 0 && dict_unknown_allowed == 0)
-           msg_fatal("dictionary %s: unknown member: %s", dict_name, member);
+       if (msg_verbose > 1)
+           msg_info("%s: %s = %s", myname, member, ret ? ret :
+                    dict->error ? "(error)" : "(notfound)");
+       return (ret);
+    } else {
+       if (msg_verbose > 1)
+           msg_info("%s: %s = %s", myname, member, "(notfound)");
+       return (0);
     }
-    if (msg_verbose > 1)
-       msg_info("%s: %s = %s", myname, member, ret ? ret : "(notfound)");
-    return (ret);
 }
 
 /* dict_delete - delete dictionary entry */
@@ -329,23 +351,12 @@ const char *dict_lookup(const char *dict_name, const char *member)
 int     dict_delete(const char *dict_name, const char *member)
 {
     const char *myname = "dict_delete";
-    DICT_NODE *node;
     DICT   *dict;
-    int     result;
 
-    if ((node = dict_node(dict_name)) == 0) {
-       if (dict_unknown_allowed == 0)
-           msg_fatal("%s: unknown dictionary: %s", myname, dict_name);
-       dict = dict_ht_open(dict_name, O_CREAT | O_RDWR, 0);
-       dict_register(dict_name, dict);
-    } else
-       dict = node->dict;
+    DICT_FIND_FOR_LOOKUP(dict, dict_name);
     if (msg_verbose > 1)
        msg_info("%s: delete %s", myname, member);
-    if ((result = dict->delete(dict, member)) != 0 && dict_unknown_allowed == 0)
-       msg_fatal("%s: dictionary %s: unknown member: %s",
-                 myname, dict_name, member);
-    return (result);
+    return (dict ? dict->delete(dict, member) : DICT_STAT_FAIL);
 }
 
 /* dict_sequence - traverse dictionary */
@@ -354,19 +365,22 @@ int     dict_sequence(const char *dict_name, const int func,
                              const char **member, const char **value)
 {
     const char *myname = "dict_sequence";
-    DICT_NODE *node;
     DICT   *dict;
 
-    if ((node = dict_node(dict_name)) == 0) {
-       if (dict_unknown_allowed == 0)
-           msg_fatal("%s: unknown dictionary: %s", myname, dict_name);
-       dict = dict_ht_open(dict_name, O_CREAT | O_RDWR, 0);
-       dict_register(dict_name, dict);
-    } else
-       dict = node->dict;
+    DICT_FIND_FOR_LOOKUP(dict, dict_name);
     if (msg_verbose > 1)
        msg_info("%s: sequence func %d", myname, func);
-    return (dict->sequence(dict, func, member, value));
+    return (dict ? dict->sequence(dict, func, member, value) : DICT_STAT_FAIL);
+}
+
+/* dict_error - return last error */
+
+int     dict_error(const char *dict_name)
+{
+    DICT   *dict;
+
+    DICT_FIND_FOR_LOOKUP(dict, dict_name);
+    return (dict ? dict->error : DICT_ERR_NONE);
 }
 
 /* dict_load_file - read entries from text file */
@@ -410,20 +424,12 @@ void    dict_load_fp(const char *dict_name, VSTREAM *fp)
     int     lineno;
     const char *err;
     struct stat st;
-    DICT_NODE *node;
     DICT   *dict;
 
     /*
      * Instantiate the dictionary even if the file is empty.
      */
-    if ((node = dict_node(dict_name)) == 0) {
-       if (dict_unknown_allowed == 0)
-           msg_fatal("%s: unknown dictionary: %s", myname, dict_name);
-       dict = dict_ht_open(dict_name, O_CREAT | O_RDWR, 0);
-       dict_register(dict_name, dict);
-    } else
-       dict = node->dict;
-
+    DICT_FIND_FOR_UPDATE(dict, dict_name);
     buf = vstring_alloc(100);
     lineno = 0;
 
@@ -435,7 +441,9 @@ void    dict_load_fp(const char *dict_name, VSTREAM *fp)
                      VSTREAM_PATH(fp), lineno, err, STR(buf));
        if (msg_verbose > 1)
            msg_info("%s: %s = %s", myname, member, val);
-       dict->update(dict, member, val);
+       if (dict->update(dict, member, val) != 0)
+           msg_fatal("%s, line %d: unable to update %s:%s",
+                     VSTREAM_PATH(fp), lineno, dict->type, dict->name);
     }
     vstring_free(buf);
     dict->owner.uid = st.st_uid;
@@ -447,14 +455,16 @@ void    dict_load_fp(const char *dict_name, VSTREAM *fp)
 static const char *dict_eval_lookup(const char *key, int unused_type,
                                            char *dict_name)
 {
-    const char *pp;
+    const char *pp = 0;
+    DICT   *dict;
 
     /*
      * XXX how would one recover?
      */
-    if ((pp = dict_lookup(dict_name, key)) == 0 && dict_errno != 0)
-       msg_fatal("dictionary %s: lookup %s: temporary error", dict_name, key);
-
+    DICT_FIND_FOR_LOOKUP(dict, dict_name);
+    if (dict != 0
+       && (pp = dict->lookup(dict, key)) == 0 && dict->error != 0)
+       msg_fatal("dictionary %s: lookup %s: operation failed", dict_name, key);
     return (pp);
 }
 
index b7811b7e234ca021f7d7692014d40f4e358ed0f1..90536a2267e51b4cdc1c3e1b03edf663b82d4f6a 100644 (file)
@@ -44,7 +44,7 @@ typedef struct DICT {
     char   *name;                      /* for diagnostics */
     int     flags;                     /* see below */
     const char *(*lookup) (struct DICT *, const char *);
-    void    (*update) (struct DICT *, const char *, const char *);
+    int     (*update) (struct DICT *, const char *, const char *);
     int     (*delete) (struct DICT *, const char *);
     int     (*sequence) (struct DICT *, int, const char **, const char **);
     void    (*close) (struct DICT *);
@@ -53,6 +53,7 @@ typedef struct DICT {
     time_t  mtime;                     /* mod time at open */
     VSTRING *fold_buf;                 /* key folding buffer */
     DICT_OWNER owner;                  /* provenance */
+    int     error;                     /* last operation only */
 } DICT;
 
 extern DICT *dict_alloc(const char *, const char *, ssize_t);
@@ -113,12 +114,24 @@ extern DICT *dict_debug(DICT *);
                                DICT_FLAG_PARANOID)
 #define DICT_FLAG_INST_MASK    ~(DICT_FLAG_IMPL_MASK | DICT_FLAG_RQST_MASK)
 
-extern int dict_unknown_allowed;
-extern int dict_errno;
-
+ /*
+  * dict->error values. Errors must be negative; smtpd_check depends on this.
+  */
 #define DICT_ERR_NONE  0               /* no error */
-#define DICT_ERR_RETRY 1               /* soft error */
-#define DICT_ERR_CONFIG        2               /* configuration error */
+#define DICT_ERR_RETRY (-1)            /* soft error */
+#define DICT_ERR_CONFIG        (-2)            /* configuration error */
+
+ /*
+  * FAIL/ERROR are suggested result values, not meant for use in comparisons.
+  */
+#define DICT_STAT_FAIL         1       /* any value > 0: notfound, conflict */
+#define DICT_STAT_SUCCESS      0       /* request satisfied */
+#define DICT_STAT_ERROR                (-1)    /* any value < 0: database error */
+
+#define DICT_ERR_VAL_RETURN(dict, err, val) do { \
+       (dict)->error = (err); \
+       return (val); \
+    } while (0)
 
  /*
   * Sequence function types.
@@ -137,13 +150,14 @@ extern ARGV *dict_mapnames(void);
 extern void dict_register(const char *, DICT *);
 extern DICT *dict_handle(const char *);
 extern void dict_unregister(const char *);
-extern void dict_update(const char *, const char *, const char *);
+extern int dict_update(const char *, const char *, const char *);
 extern const char *dict_lookup(const char *, const char *);
 extern int dict_delete(const char *, const char *);
 extern int dict_sequence(const char *, const int, const char **, const char **);
 extern void dict_load_file(const char *, const char *);
 extern void dict_load_fp(const char *, VSTREAM *);
 extern const char *dict_eval(const char *, const char *, int);
+extern int dict_error(const char *);
 
  /*
   * Low-level interface, with physical dictionary handles.
index 0f97d1b6ea42b54106a83bc32a11a52c4191ef31..b684210210218a23fae07402782618e1f84b8439 100644 (file)
@@ -71,8 +71,8 @@ static const char *dict_default_lookup(DICT *dict, const char *unused_key)
 
 /* dict_default_update - trap unimplemented operation */
 
-static void dict_default_update(DICT *dict, const char *unused_key,
-                                       const char *unused_value)
+static int dict_default_update(DICT *dict, const char *unused_key,
+                                      const char *unused_value)
 {
     msg_fatal("%s table %s: update operation is not supported",
              dict->type, dict->name);
@@ -123,6 +123,7 @@ DICT   *dict_alloc(const char *dict_type, const char *dict_name, ssize_t size)
     dict->fold_buf = 0;
     dict->owner.status = DICT_OWNER_UNKNOWN;
     dict->owner.uid = ~0;
+    dict->error = DICT_ERR_NONE;
     return dict;
 }
 
index 506a7d09b723169269f8a49a27333d5a2b5b3124..94907dd128b56366ac6ea1d0f334c8ac619917a5 100644 (file)
 /* .IP table
 /*     A bare dictonary handle.
 /* DIAGNOSTICS
-/*     These routines terminate with a fatal run-time error
-/*     for unrecoverable database errors. This allows the
-/*     program to restart and reset the database to an
-/*     empty initial state.
+/*     When a request is satisfied, the lookup routine returns
+/*     non-null, and the update, delete and sequence routines
+/*     return zero.  The cache->error value is zero when a request
+/*     could not be satisfied because an item did not exist (delete,
+/*     sequence) or if it could not be updated. The cache->error
+/*     value is non-zero only when a request could not be satisfied,
+/*     and the cause was a database error.
+/*
+/*     Cache access errors are logged with a warning message. To
+/*     avoid spamming the log, each type of operation logs no more
+/*     than one cache access error per second, per cache. Specify
+/*     the DICT_CACHE_FLAG_VERBOSE flag (see above) to log all
+/*     warnings.
 /* BUGS
 /*     There should be a way to suspend automatic program suicide
 /*     until a cache cleanup run is completed. Some entries may
@@ -201,6 +210,7 @@ struct DICT_CACHE {
     int     cache_flags;               /* see below */
     int     user_flags;                        /* logging */
     DICT   *db;                                /* database handle */
+    int     error;                     /* last operation only */
 
     /* Delete-behind support. */
     char   *saved_curr_key;            /* "current" cache lookup key */
@@ -212,10 +222,22 @@ struct DICT_CACHE {
     char   *exp_context;               /* call-back context */
     int     retained;                  /* entries retained in cleanup run */
     int     dropped;                   /* entries removed in cleanup run */
+
+    /* Rate-limited logging support. */
+    int     log_delay;
+    time_t  upd_log_stamp;             /* last update warning */
+    time_t  get_log_stamp;             /* last lookup warning */
+    time_t  del_log_stamp;             /* last delete warning */
+    time_t  seq_log_stamp;             /* last sequence warning */
 };
 
 #define DC_FLAG_DEL_SAVED_CURRENT_KEY  (1<<0)  /* delete-behind is scheduled */
 
+ /*
+  * Don't log cache access errors more than once per second.
+  */
+#define DC_DEF_LOG_DELAY       1
+
  /*
   * Macros to make obscure code more readable.
   */
@@ -243,6 +265,7 @@ const char *dict_cache_lookup(DICT_CACHE *cp, const char *cache_key)
 {
     const char *myname = "dict_cache_lookup";
     const char *cache_val;
+    DICT   *db = cp->db;
 
     /*
      * Search for the cache entry. Don't return an entry that is scheduled
@@ -253,29 +276,29 @@ const char *dict_cache_lookup(DICT_CACHE *cp, const char *cache_key)
        if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE)
            msg_info("%s: key=%s (pretend not found  - scheduled for deletion)",
                     myname, cache_key);
-       dict_errno = 0;
-       return (0);
+       DICT_ERR_VAL_RETURN(cp, DICT_ERR_NONE, (char *) 0);
     } else {
-       cache_val = dict_get(cp->db, cache_key);
-#if 0
-       if (cache_val == 0 && dict_errno != 0)
-           msg_warn("%s: cache lookup for '%s' failed due to error",
-                    cp->name, cache_key);
-#endif
+       cache_val = dict_get(db, cache_key);
+       if (cache_val == 0 && db->error != 0)
+           msg_rate_delay(&cp->get_log_stamp, cp->log_delay, msg_warn,
+                          "%s: cache lookup for '%s' failed due to error",
+                          cp->name, cache_key);
        if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE)
            msg_info("%s: key=%s value=%s", myname, cache_key,
-                    cache_val ? cache_val : dict_errno ?
+                    cache_val ? cache_val : db->error ?
                     "error" : "(not found)");
-       return (cache_val);
+       DICT_ERR_VAL_RETURN(cp, db->error, cache_val);
     }
 }
 
 /* dict_cache_update - save entry to cache */
 
-void    dict_cache_update(DICT_CACHE *cp, const char *cache_key,
+int     dict_cache_update(DICT_CACHE *cp, const char *cache_key,
                                  const char *cache_val)
 {
     const char *myname = "dict_cache_update";
+    DICT   *db = cp->db;
+    int     put_res;
 
     /*
      * Store the cache entry and cancel the delete-behind operation.
@@ -288,7 +311,11 @@ void    dict_cache_update(DICT_CACHE *cp, const char *cache_key,
     }
     if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE)
        msg_info("%s: key=%s value=%s", myname, cache_key, cache_val);
-    dict_put(cp->db, cache_key, cache_val);
+    put_res = dict_put(db, cache_key, cache_val);
+    if (put_res != 0)
+       msg_rate_delay(&cp->upd_log_stamp, cp->log_delay, msg_warn,
+                 "%s: could not update entry for %s", cp->name, cache_key);
+    DICT_ERR_VAL_RETURN(cp, db->error, put_res);
 }
 
 /* dict_cache_delete - delete entry from cache */
@@ -296,7 +323,8 @@ void    dict_cache_update(DICT_CACHE *cp, const char *cache_key,
 int     dict_cache_delete(DICT_CACHE *cp, const char *cache_key)
 {
     const char *myname = "dict_cache_delete";
-    int     zero_means_found;
+    int     del_res;
+    DICT   *db = cp->db;
 
     /*
      * Delete the entry, unless we would delete the current first/next entry.
@@ -308,18 +336,18 @@ int     dict_cache_delete(DICT_CACHE *cp, const char *cache_key)
        if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE)
            msg_info("%s: key=%s (current entry - schedule for delete-behind)",
                     myname, cache_key);
-       zero_means_found = 0;
+       DICT_ERR_VAL_RETURN(cp, DICT_ERR_NONE, DICT_STAT_SUCCESS);
     } else {
-       zero_means_found = dict_del(cp->db, cache_key);
-#if 0
-       if (zero_means_found != 0)
-           msg_warn("%s: could not delete entry for %s", cp->name, cache_key);
-#endif
+       del_res = dict_del(db, cache_key);
+       if (del_res != 0)
+           msg_rate_delay(&cp->del_log_stamp, cp->log_delay, msg_warn,
+                 "%s: could not delete entry for %s", cp->name, cache_key);
        if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE)
            msg_info("%s: key=%s (%s)", myname, cache_key,
-                    zero_means_found == 0 ? "found" : "not found");
+                    del_res == 0 ? "found" :
+                    db->error ? "error" : "not found");
+       DICT_ERR_VAL_RETURN(cp, db->error, del_res);
     }
-    return (zero_means_found);
 }
 
 /* dict_cache_sequence - look up the first/next cache entry */
@@ -329,26 +357,31 @@ int     dict_cache_sequence(DICT_CACHE *cp, int first_next,
                                    const char **cache_val)
 {
     const char *myname = "dict_cache_sequence";
-    int     zero_means_found;
+    int     seq_res;
     const char *raw_cache_key;
     const char *raw_cache_val;
     char   *previous_curr_key;
     char   *previous_curr_val;
+    DICT   *db = cp->db;
 
     /*
      * Find the first or next database entry. Hide the record with the cache
      * cleanup completion time stamp.
      */
-    zero_means_found =
-       dict_seq(cp->db, first_next, &raw_cache_key, &raw_cache_val);
-    if (zero_means_found == 0
+    seq_res = dict_seq(db, first_next, &raw_cache_key, &raw_cache_val);
+    if (seq_res == 0
        && strcmp(raw_cache_key, DC_LAST_CACHE_CLEANUP_COMPLETED) == 0)
-       zero_means_found =
-           dict_seq(cp->db, DICT_SEQ_FUN_NEXT, &raw_cache_key, &raw_cache_val);
+       seq_res =
+           dict_seq(db, DICT_SEQ_FUN_NEXT, &raw_cache_key, &raw_cache_val);
     if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE)
        msg_info("%s: key=%s value=%s", myname,
-                zero_means_found == 0 ? raw_cache_key : "(not found)",
-                zero_means_found == 0 ? raw_cache_val : "(not found)");
+                seq_res == 0 ? raw_cache_key : db->error ?
+                "(error)" : "(not found)",
+                seq_res == 0 ? raw_cache_val : db->error ?
+                "(error)" : "(not found)");
+    if (db->error)
+       msg_rate_delay(&cp->seq_log_stamp, cp->log_delay, msg_warn,
+                      "%s: sequence error", cp->name);
 
     /*
      * Save the current cache_key and cache_val before they are clobbered by
@@ -360,7 +393,7 @@ int     dict_cache_sequence(DICT_CACHE *cp, int first_next,
      */
     previous_curr_key = cp->saved_curr_key;
     previous_curr_val = cp->saved_curr_val;
-    if (zero_means_found == 0) {
+    if (seq_res == 0) {
        cp->saved_curr_key = mystrdup(raw_cache_key);
        cp->saved_curr_val = mystrdup(raw_cache_val);
     } else {
@@ -371,14 +404,15 @@ int     dict_cache_sequence(DICT_CACHE *cp, int first_next,
     /*
      * Delete behind.
      */
-    if (DC_IS_SCHEDULED_FOR_DELETE_BEHIND(cp)) {
+    if (db->error == 0 && DC_IS_SCHEDULED_FOR_DELETE_BEHIND(cp)) {
        DC_CANCEL_DELETE_BEHIND(cp);
        if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE)
            msg_info("%s: delete-behind key=%s value=%s",
                     myname, previous_curr_key, previous_curr_val);
-       if (dict_del(cp->db, previous_curr_key) != 0)
-           msg_warn("%s: could not delete entry for %s",
-                    cp->name, previous_curr_key);
+       if (dict_del(db, previous_curr_key) != 0)
+           msg_rate_delay(&cp->del_log_stamp, cp->log_delay, msg_warn,
+                          "%s: could not delete entry for %s",
+                          cp->name, previous_curr_key);
     }
 
     /*
@@ -394,7 +428,7 @@ int     dict_cache_sequence(DICT_CACHE *cp, int first_next,
      */
     *cache_key = (cp)->saved_curr_key;
     *cache_val = (cp)->saved_curr_val;
-    return (zero_means_found);
+    DICT_ERR_VAL_RETURN(cp, db->error, seq_res);
 }
 
 /* dict_cache_delete_behind_reset - reset "delete behind" state */
@@ -476,14 +510,11 @@ static void dict_cache_clean_event(int unused_event, char *cache_context)
     /*
      * Cache cleanup completed. Report vital statistics.
      */
-#if 0
-    else if (dict_errno != 0) {
-       msg_warn("%s: cache cleanup scan failed due to error", cp->name);
+    else if (cp->error != 0) {
+       msg_warn("%s: cache cleanup scan terminated due to error", cp->name);
        dict_cache_clean_stat_log_reset(cp, "partial");
        next_interval = cp->exp_interval;
-    }
-#endif
-    else {
+    } else {
        if (cp->user_flags & DICT_CACHE_FLAG_VERBOSE)
            msg_info("%s: done %s cache cleanup scan", myname, cp->name);
        dict_cache_clean_stat_log_reset(cp, "full");
@@ -518,6 +549,8 @@ void    dict_cache_control(DICT_CACHE *cp,...)
            break;
        case DICT_CACHE_CTL_FLAGS:
            cp->user_flags = va_arg(ap, int);
+           cp->log_delay = (cp->user_flags & DICT_CACHE_FLAG_VERBOSE) ?
+               0 : DC_DEF_LOG_DELAY;
            break;
        case DICT_CACHE_CTL_INTERVAL:
            cp->exp_interval = va_arg(ap, int);
@@ -606,6 +639,9 @@ DICT_CACHE *dict_cache_open(const char *dbname, int open_flags, int dict_flags)
     cp->exp_context = 0;
     cp->retained = 0;
     cp->dropped = 0;
+    cp->log_delay = DC_DEF_LOG_DELAY;
+    cp->upd_log_stamp = cp->get_log_stamp =
+       cp->del_log_stamp = cp->seq_log_stamp = 0;
 
     return (cp);
 }
index 33d606124a438132b4b7151f791be2e605bb73de..20dcab6130644322f596a470008acf45e515f9df 100644 (file)
@@ -25,7 +25,7 @@ typedef int (*DICT_CACHE_VALIDATOR_FN) (const char *, const char *, char *);
 extern DICT_CACHE *dict_cache_open(const char *, int, int);
 extern void dict_cache_close(DICT_CACHE *);
 extern const char *dict_cache_lookup(DICT_CACHE *, const char *);
-extern void dict_cache_update(DICT_CACHE *, const char *, const char *);
+extern int dict_cache_update(DICT_CACHE *, const char *, const char *);
 extern int dict_cache_delete(DICT_CACHE *, const char *);
 extern int dict_cache_sequence(DICT_CACHE *, int, const char **, const char **);
 extern void dict_cache_control(DICT_CACHE *,...);
index 36437abc3e9001898e8332dcb0e77396dec3f200..099ecc99d567ffa94d007ddc60a6863ddd1c2187 100644 (file)
@@ -103,7 +103,7 @@ static const char *dict_cdbq_lookup(DICT *dict, const char *name)
     static unsigned len;
     const char *result = 0;
 
-    dict_errno = 0;
+    dict->error = 0;
 
     /* CDB is constant, so do not try to acquire a lock. */
 
@@ -229,12 +229,14 @@ static DICT *dict_cdbq_open(const char *path, int dict_flags)
 
 /* dict_cdbm_update - add database entry, create mode */
 
-static void dict_cdbm_update(DICT *dict, const char *name, const char *value)
+static int dict_cdbm_update(DICT *dict, const char *name, const char *value)
 {
     DICT_CDBM *dict_cdbm = (DICT_CDBM *) dict;
     unsigned ksize, vsize;
     int     r;
 
+    dict->error = 0;
+
     /*
      * Optionally fold the key.
      */
@@ -281,9 +283,11 @@ static void dict_cdbm_update(DICT *dict, const char *name, const char *value)
            msg_fatal("%s: duplicate entry: \"%s\"",
                      dict_cdbm->dict.name, name);
     }
+    return (r);
 #else
     if (cdb_make_add(&dict_cdbm->cdbm, name, ksize, value, vsize) < 0)
        msg_fatal("error writing %s: %m", dict_cdbm->tmp_path);
+    return (0);
 #endif
 }
 
index 82480119d2a452c9f79881b35c499b30add1cf0a..97f4867db3e76fccae1cc0e5623b93f8fd7abfe3 100644 (file)
@@ -79,7 +79,7 @@ static const char *dict_cidr_lookup(DICT *dict, const char *key)
     if (msg_verbose)
        msg_info("dict_cidr_lookup: %s: %s", dict->name, key);
 
-    dict_errno = 0;
+    dict->error = 0;
 
     if ((entry = (DICT_CIDR_ENTRY *)
         cidr_match_execute(&(dict_cidr->head->cidr_info), key)) != 0)
index 7fb00985a96c49c4eae14d3b3215571ccc69c1ba..898dab53a487d46d1eea55755ffc36284f1c19c6 100644 (file)
@@ -181,13 +181,14 @@ static const char *dict_db_lookup(DICT *dict, const char *name)
     int     status;
     const char *result = 0;
 
+    dict->error = 0;
+
     /*
      * Sanity check.
      */
     if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
        msg_panic("dict_db_lookup: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag");
 
-    dict_errno = 0;
     memset(&db_key, 0, sizeof(db_key));
     memset(&db_value, 0, sizeof(db_value));
 
@@ -250,7 +251,7 @@ static const char *dict_db_lookup(DICT *dict, const char *name)
 
 /* dict_db_update - add or update database entry */
 
-static void dict_db_update(DICT *dict, const char *name, const char *value)
+static int dict_db_update(DICT *dict, const char *name, const char *value)
 {
     DICT_DB *dict_db = (DICT_DB *) dict;
     DB     *db = dict_db->db;
@@ -258,6 +259,8 @@ static void dict_db_update(DICT *dict, const char *name, const char *value)
     DBT     db_value;
     int     status;
 
+    dict->error = 0;
+
     /*
      * Sanity check.
      */
@@ -332,6 +335,8 @@ static void dict_db_update(DICT *dict, const char *name, const char *value)
     if ((dict->flags & DICT_FLAG_LOCK)
        && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
        msg_fatal("%s: unlock dictionary: %m", dict_db->dict.name);
+
+    return (status);
 }
 
 /* delete one entry from the dictionary */
@@ -344,6 +349,8 @@ static int dict_db_delete(DICT *dict, const char *name)
     int     status = 1;
     int     flags = 0;
 
+    dict->error = 0;
+
     /*
      * Sanity check.
      */
@@ -420,12 +427,13 @@ static int dict_db_sequence(DICT *dict, int function,
     int     status = 0;
     int     db_function;
 
+    dict->error = 0;
+
 #if DB_VERSION_MAJOR > 1
 
     /*
      * Initialize.
      */
-    dict_errno = 0;
     memset(&db_key, 0, sizeof(db_key));
     memset(&db_value, 0, sizeof(db_value));
 
index 0a0a256a10897681e5b49ff9f1b1a9c0f538a713..bdc4c3888995ebdeacc17ce4e68cd16b928e70aa 100644 (file)
@@ -82,14 +82,14 @@ static const char *dict_dbm_lookup(DICT *dict, const char *name)
     datum   dbm_value;
     const char *result = 0;
 
+    dict->error = 0;
+
     /*
      * Sanity check.
      */
     if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
        msg_panic("dict_dbm_lookup: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag");
 
-    dict_errno = 0;
-
     /*
      * Optionally fold the key.
      */
@@ -147,13 +147,15 @@ static const char *dict_dbm_lookup(DICT *dict, const char *name)
 
 /* dict_dbm_update - add or update database entry */
 
-static void dict_dbm_update(DICT *dict, const char *name, const char *value)
+static int dict_dbm_update(DICT *dict, const char *name, const char *value)
 {
     DICT_DBM *dict_dbm = (DICT_DBM *) dict;
     datum   dbm_key;
     datum   dbm_value;
     int     status;
 
+    dict->error = 0;
+
     /*
      * Sanity check.
      */
@@ -223,6 +225,8 @@ static void dict_dbm_update(DICT *dict, const char *name, const char *value)
     if ((dict->flags & DICT_FLAG_LOCK)
        && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
        msg_fatal("%s: unlock dictionary: %m", dict_dbm->dict.name);
+
+    return (status);
 }
 
 /* dict_dbm_delete - delete one entry from the dictionary */
@@ -233,6 +237,8 @@ static int dict_dbm_delete(DICT *dict, const char *name)
     datum   dbm_key;
     int     status = 1;
 
+    dict->error = 0;
+
     /*
      * Sanity check.
      */
@@ -311,6 +317,8 @@ static int dict_dbm_sequence(DICT *dict, int function,
     datum   dbm_value;
     int     status;
 
+    dict->error = 0;
+
     /*
      * Acquire a shared lock.
      */
index 9b85f1e54c18f3e2ff707a8ea154f20b89735fbf..3d9a44325f3a656232ce7a4f14b0bad109ff43f9 100644 (file)
@@ -56,23 +56,28 @@ typedef struct {
 static const char *dict_debug_lookup(DICT *dict, const char *key)
 {
     DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict;
+    DICT   *real_dict = dict_debug->real_dict;
     const char *result;
 
-    result = dict_get(dict_debug->real_dict, key);
+    result = dict_get(real_dict, key);
     msg_info("%s:%s lookup: \"%s\" = \"%s\"", dict->type, dict->name, key,
-            result ? result : dict_errno ? "try again" : "not_found");
-    return (result);
+            result ? result : real_dict->error ? "error" : "not_found");
+    DICT_ERR_VAL_RETURN(dict, real_dict->error, result);
 }
 
 /* dict_debug_update - log update operation */
 
-static void dict_debug_update(DICT *dict, const char *key, const char *value)
+static int dict_debug_update(DICT *dict, const char *key, const char *value)
 {
     DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict;
+    DICT   *real_dict = dict_debug->real_dict;
+    int     result;
 
-    msg_info("%s:%s update: \"%s\" = \"%s\"", dict->type, dict->name,
-            key, value);
-    dict_put(dict_debug->real_dict, key, value);
+    result = dict_put(real_dict, key, value);
+    msg_info("%s:%s update: \"%s\" = \"%s\": %s", dict->type, dict->name,
+            key, value, result == 0 ? "success" : real_dict->error ?
+            "error" : "failed");
+    DICT_ERR_VAL_RETURN(dict, real_dict->error, result);
 }
 
 /* dict_debug_delete - log delete operation */
@@ -80,12 +85,14 @@ static void dict_debug_update(DICT *dict, const char *key, const char *value)
 static int dict_debug_delete(DICT *dict, const char *key)
 {
     DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict;
+    DICT   *real_dict = dict_debug->real_dict;
     int     result;
 
-    result = dict_del(dict_debug->real_dict, key);
-    msg_info("%s:%s delete: \"%s\" = \"%s\"", dict->type, dict->name, key,
-            result ? "failed" : "success");
-    return (result);
+    result = dict_del(real_dict, key);
+    msg_info("%s:%s delete: \"%s\": %s", dict->type, dict->name, key,
+            result == 0 ? "success" : real_dict->error ?
+            "error" : "failed");
+    DICT_ERR_VAL_RETURN(dict, real_dict->error, result);
 }
 
 /* dict_debug_sequence - log sequence operation */
@@ -94,15 +101,16 @@ static int dict_debug_sequence(DICT *dict, int function,
                                       const char **key, const char **value)
 {
     DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict;
+    DICT   *real_dict = dict_debug->real_dict;
     int     result;
 
-    result = dict_seq(dict_debug->real_dict, function, key, value);
+    result = dict_seq(real_dict, function, key, value);
     if (result == 0)
        msg_info("%s:%s sequence: \"%s\" = \"%s\"", dict->type, dict->name,
                 *key, *value);
     else
        msg_info("%s:%s sequence: found EOF", dict->type, dict->name);
-    return (result);
+    DICT_ERR_VAL_RETURN(dict, real_dict->error, result);
 }
 
 /* dict_debug_close - log operation */
index bc15d6c92d18ee4c4694baade9417ae6b6efc4ae..1635b8d8263d31be4c4d7ccd9a9d1602e68c6f79 100644 (file)
@@ -48,8 +48,9 @@
 
 /* dict_env_update - update environment array */
 
-static void dict_env_update(DICT *dict, const char *name, const char *value)
+static int dict_env_update(DICT *dict, const char *name, const char *value)
 {
+    dict->error = 0;
 
     /*
      * Optionally fold the key.
@@ -62,13 +63,15 @@ static void dict_env_update(DICT *dict, const char *name, const char *value)
     }
     if (setenv(name, value, 1))
        msg_fatal("setenv: %m");
+
+    return (DICT_STAT_SUCCESS);
 }
 
 /* dict_env_lookup - access environment array */
 
 static const char *dict_env_lookup(DICT *dict, const char *name)
 {
-    dict_errno = 0;
+    dict->error = 0;
 
     /*
      * Optionally fold the key.
index b0ad3f2c573eedcb089fcf02a6c1ae06965e0d33..c4f8f54d5c3246bb67269c7304ae90829a6babea 100644 (file)
@@ -12,7 +12,7 @@
 /*     int     dict_flags;
 /* DESCRIPTION
 /*     dict_fail_open() implements a dummy dictionary that fails
-/*     all operations. The name specifies the dict_errno value.
+/*     all operations. The name can be used for logging.
 /* SEE ALSO
 /*     dict(3) generic dictionary manager
 /* LICENSE
@@ -29,7 +29,6 @@
 /* System library. */
 
 #include <sys_defs.h>
-#include <stdlib.h>
 
 /* Utility library. */
 
@@ -48,22 +47,21 @@ typedef struct {
 /* dict_fail_sequence - fail lookup */
 
 static int dict_fail_sequence(DICT *dict, int unused_func,
-                                      const char **key, const char **value)
+                                     const char **key, const char **value)
 {
     DICT_FAIL *dp = (DICT_FAIL *) dict;
 
-    dict_errno = dp->dict_errno;
-    return (1);
+    DICT_ERR_VAL_RETURN(dict, dp->dict_errno, DICT_STAT_ERROR);
 }
 
 /* dict_fail_update - fail lookup */
 
-static void dict_fail_update(DICT *dict, const char *unused_name,
-                                    const char *unused_value)
+static int dict_fail_update(DICT *dict, const char *unused_name,
+                                   const char *unused_value)
 {
     DICT_FAIL *dp = (DICT_FAIL *) dict;
 
-    dict_errno = dp->dict_errno;
+    DICT_ERR_VAL_RETURN(dict, dp->dict_errno, DICT_STAT_ERROR);
 }
 
 /* dict_fail_lookup - fail lookup */
@@ -72,8 +70,7 @@ static const char *dict_fail_lookup(DICT *dict, const char *unused_name)
 {
     DICT_FAIL *dp = (DICT_FAIL *) dict;
 
-    dict_errno = dp->dict_errno;
-    return (0);
+    DICT_ERR_VAL_RETURN(dict, dp->dict_errno, (char *) 0);
 }
 
 /* dict_fail_delete - fail delete */
@@ -82,8 +79,7 @@ static int dict_fail_delete(DICT *dict, const char *unused_name)
 {
     DICT_FAIL *dp = (DICT_FAIL *) dict;
 
-    dict_errno = dp->dict_errno;
-    return (-1);
+    DICT_ERR_VAL_RETURN(dict, dp->dict_errno, DICT_STAT_ERROR);
 }
 
 /* dict_fail_close - close fail dictionary */
@@ -108,9 +104,7 @@ DICT   *dict_fail_open(const char *name, int open_flags, int dict_flags)
     dp->dict.sequence = dict_fail_sequence;
     dp->dict.close = dict_fail_close;
     dp->dict.flags = dict_flags | DICT_FLAG_PATTERN;
-    dp->dict_errno = atoi(name);
-    if (dp->dict_errno == 0)
-       dp->dict_errno = 1;
+    dp->dict_errno = DICT_ERR_RETRY;
     dp->dict.owner.status = DICT_OWNER_TRUSTED;
     return (DICT_DEBUG (&dp->dict));
 }
index 0eff0810a0bc2494bed930a1329e932b7122de79..aaa4f90fe9c3521047c50ca1dc0d1ede65b32006 100644 (file)
@@ -54,8 +54,6 @@ static const char *dict_ht_lookup(DICT *dict, const char *name)
 {
     DICT_HT *dict_ht = (DICT_HT *) dict;
 
-    dict_errno = 0;
-
     /*
      * Optionally fold the key.
      */
@@ -65,12 +63,12 @@ static const char *dict_ht_lookup(DICT *dict, const char *name)
        vstring_strcpy(dict->fold_buf, name);
        name = lowercase(vstring_str(dict->fold_buf));
     }
-    return (htable_find(dict_ht->table, name));
+    DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, htable_find(dict_ht->table, name));
 }
 
 /* dict_ht_update - add or update hash-table entry */
 
-static void dict_ht_update(DICT *dict, const char *name, const char *value)
+static int dict_ht_update(DICT *dict, const char *name, const char *value)
 {
     DICT_HT *dict_ht = (DICT_HT *) dict;
     HTABLE_INFO *ht;
@@ -91,6 +89,7 @@ static void dict_ht_update(DICT *dict, const char *name, const char *value)
        ht = htable_enter(dict_ht->table, name, (char *) 0);
     }
     ht->value = saved_value;
+    DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_SUCCESS);
 }
 
 /* dict_ht_sequence - first/next iterator */
@@ -108,11 +107,11 @@ static int dict_ht_sequence(DICT *dict, int how, const char **name,
     if (ht != 0) {
        *name = ht->key;
        *value = ht->value;
-       return (0);
+       DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_SUCCESS);
     } else {
        *name = 0;
        *value = 0;
-       return (1);
+       DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_FAIL);
     }
 }
 
index 569188c0cafdfbf5366fda3e0e28c217ba6e9e9d..4210c0b64c8eccd6b8bf536587a53dc34d6068f1 100644 (file)
@@ -80,8 +80,6 @@ static const char *dict_ni_do_lookup(char *path, char *key_prop,
     ni_status r;
     ni_id   dir;
 
-    dict_errno = 0;
-
     if (msg_verbose)
        msg_info("ni_lookup %s %s=%s", path, key_prop, key_value);
 
@@ -150,6 +148,8 @@ static const char *dict_ni_lookup(DICT *dict, const char *key)
 {
     DICT_NI *d = (DICT_NI *) dict;
 
+    dict->error = 0;
+
     /*
      * Optionally fold the key.
      */
index 27a20a54ef8a3cbd3d83ccff2cc47693e727fc2a..a06e5f359d14519a1b041066982b52dbadf4f3f4 100644 (file)
@@ -144,13 +144,14 @@ static const char *dict_nis_lookup(DICT *dict, const char *key)
     int     err;
     static VSTRING *buf;
 
+    dict->error = 0;
+
     /*
      * Sanity check.
      */
     if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
        msg_panic("dict_nis_lookup: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag");
 
-    dict_errno = 0;
     if (dict_nis_domain == dict_nis_disabled)
        return (0);
 
@@ -204,7 +205,7 @@ static const char *dict_nis_lookup(DICT *dict, const char *key)
        msg_warn("lookup %s, NIS domain %s, map %s: %s",
                 key, dict_nis_domain, dict_nis->dict.name,
                 dict_nis_strerror(err));
-       dict_errno = DICT_ERR_RETRY;
+       dict->error = DICT_ERR_RETRY;
     }
     return (0);
 }
index c10fa45b9dd5449679b3552bbb308a01f1ef3349..819bf0750fc4d0ad475befcec1521054ef84d14f 100644 (file)
@@ -126,10 +126,11 @@ static const char *dict_nisplus_lookup(DICT *dict, const char *key)
     int     last_col;
     int     ch;
 
+    dict->error = 0;
+
     /*
      * Initialize.
      */
-    dict_errno = 0;
     if (quoted_key == 0) {
        query = vstring_alloc(100);
        retval = vstring_alloc(100);
@@ -222,7 +223,7 @@ static const char *dict_nisplus_lookup(DICT *dict, const char *key)
            msg_warn("lookup %s, NIS+ map %s: %s",
                     key, dict_nisplus->dict.name,
                     nis_sperrno(reply->status));
-           dict_errno = DICT_ERR_RETRY;
+           dict->error = DICT_ERR_RETRY;
        } else {
            if (msg_verbose)
                msg_info("%s: not found: query %s", myname, STR(query));
index 76d946be42095b57298d521fa6910439ad543903..49e2b2c3cfa66ddfbc1a126bd6fb708d4263efec 100644 (file)
@@ -17,7 +17,7 @@
 /*     int     open_flags;
 /*     int     dict_flags;
 /*
-/*     void    dict_put(dict, key, value)
+/*     int     dict_put(dict, key, value)
 /*     DICT    *dict;
 /*     const char *key;
 /*     const char *value;
@@ -30,7 +30,7 @@
 /*     DICT    *dict;
 /*     const char *key;
 /*
-/*     void    dict_seq(dict, func, key, value)
+/*     int     dict_seq(dict, func, key, value)
 /*     DICT    *dict;
 /*     int     func;
 /*     const char **key;
@@ -99,7 +99,7 @@
 /*     With file-based maps, flush I/O buffers to file after each update.
 /*     Thus feature is not supported with some file-based dictionaries.
 /* .IP DICT_FLAG_NO_REGSUB
-/*      Disallow regular expression substitution from left-hand side data
+/*     Disallow regular expression substitution from left-hand side data
 /*     into the right-hand side.
 /* .IP DICT_FLAG_NO_PROXY
 /*     Disallow access through the \fBproxymap\fR service.
 /*     or if the result is to survive multiple table lookups.
 /*
 /*     dict_put() stores the specified key and value into the named
-/*     dictionary.
+/*     dictionary. A zero (DICT_STAT_SUCCESS) result means the
+/*     update was made.
 /*
-/*     dict_del() removes a dictionary entry, and returns zero
-/*     in case of success.
+/*     dict_del() removes a dictionary entry, and returns
+/*     DICT_STAT_SUCCESS in case of success.
 /*
 /*     dict_seq() iterates over all members in the named dictionary.
 /*     func is define DICT_SEQ_FUN_FIRST (select first member) or
-/*     DICT_SEQ_FUN_NEXT (select next member). A zero result means
-/*     that an entry was found.
+/*     DICT_SEQ_FUN_NEXT (select next member). A zero (DICT_STAT_SUCCESS)
+/*     result means that an entry was found.
 /*
 /*     dict_close() closes the specified dictionary and cleans up the
 /*     associated data structures.
 /* DIAGNOSTICS
 /*     Fatal error: open error, unsupported dictionary type, attempt to
 /*     update non-writable dictionary.
+/*
+/*     The lookup routine returns non-null when the request is
+/*     satisfied. The update, delete and sequence routines return
+/*     zero (DICT_STAT_SUCCESS) when the request is satisfied.
+/*     The dict->errno value is non-zero only when the last operation
+/*     was not satisfied due to a dictionary access error. This
+/*     can have the following values:
+/* .IP DICT_ERR_NONE(zero)
+/*     There was no dictionary access error. For example, the
+/*     request was satisfied, the requested information did not
+/*     exist in the dictionary, or the information already existed
+/*     when it should not exist (collision).
+/* .IP DICT_ERR_RETRY(<0)
+/*     The dictionary was temporarily unavailable. This can happen
+/*     with network-based services.
+/* .IP DICT_ERR_CONFIG(<0)
+/*     The dictionary was unavailable due to a configuration error.
+/* .PP
+/*     Generally, a program is expected to test the function result
+/*     value for "success" first. If the operation was not successful,
+/*     a program is expected to test for a non-zero dict->error
+/*     status to distinguish between a data notfound/collision
+/*     condition or a dictionary access error.
 /* LICENSE
 /* .ad
 /* .fi
index f7a692153f6acce9b2e4356ab30fedc076a055cd..067416442fbf3b6dcb5e88df4b3342e31b8829ee 100644 (file)
@@ -257,7 +257,7 @@ static const char *dict_pcre_lookup(DICT *dict, const char *lookup_string)
     DICT_PCRE_EXPAND_CONTEXT ctxt;
     int     nesting = 0;
 
-    dict_errno = 0;
+    dict->error = 0;
 
     if (msg_verbose)
        msg_info("dict_pcre_lookup: %s: %s", dict->name, lookup_string);
index c88d2bd5559cb385587bc4c00709be04dc1f6102..b7b08c62f2b19755c0632864f69d025a13433fd8 100644 (file)
@@ -217,7 +217,7 @@ static const char *dict_regexp_lookup(DICT *dict, const char *lookup_string)
     int     error;
     int     nesting = 0;
 
-    dict_errno = 0;
+    dict->error = 0;
 
     if (msg_verbose)
        msg_info("dict_regexp_lookup: %s: %s", dict->name, lookup_string);
index c6a3749142a474d17cbccba6460a70d58289c291..3a30d9c65fbbd01ac8a5f4c6b1a62b6e8464a513 100644 (file)
@@ -76,14 +76,14 @@ static const char *dict_sdbm_lookup(DICT *dict, const char *name)
     datum   dbm_value;
     const char *result = 0;
 
+    dict->error = 0;
+
     /*
      * Sanity check.
      */
     if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
        msg_panic("dict_sdbm_lookup: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag");
 
-    dict_errno = 0;
-
     /*
      * Optionally fold the key.
      */
@@ -141,13 +141,15 @@ static const char *dict_sdbm_lookup(DICT *dict, const char *name)
 
 /* dict_sdbm_update - add or update database entry */
 
-static void dict_sdbm_update(DICT *dict, const char *name, const char *value)
+static int dict_sdbm_update(DICT *dict, const char *name, const char *value)
 {
     DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict;
     datum   dbm_key;
     datum   dbm_value;
     int     status;
 
+    dict->error = 0;
+
     /*
      * Sanity check.
      */
@@ -217,6 +219,8 @@ static void dict_sdbm_update(DICT *dict, const char *name, const char *value)
     if ((dict->flags & DICT_FLAG_LOCK)
        && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
        msg_fatal("%s: unlock dictionary: %m", dict_sdbm->dict.name);
+
+    return (status);
 }
 
 /* dict_sdbm_delete - delete one entry from the dictionary */
@@ -227,6 +231,8 @@ static int dict_sdbm_delete(DICT *dict, const char *name)
     datum   dbm_key;
     int     status = 1;
 
+    dict->error = 0;
+
     /*
      * Sanity check.
      */
@@ -303,6 +309,9 @@ static int dict_sdbm_sequence(DICT *dict, const int function,
     DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict;
     datum   dbm_key;
     datum   dbm_value;
+    int     status;
+
+    dict->error = 0;
 
     /*
      * Acquire a shared lock.
@@ -344,6 +353,7 @@ static int dict_sdbm_sequence(DICT *dict, const int function,
             * Copy the value so that it is guaranteed null terminated.
             */
            *value = SCOPY(dict_sdbm->val_buf, dbm_value.dptr, dbm_value.dsize);
+           status = 0;
        } else {
 
            /*
@@ -352,7 +362,7 @@ static int dict_sdbm_sequence(DICT *dict, const int function,
             */
            if (sdbm_error(dict_sdbm->dbm))
                msg_fatal("error seeking %s: %m", dict_sdbm->dict.name);
-           return (1);                         /* no error: eof/not found
+           status = 1;                         /* no error: eof/not found
                                                 * (should not happen!) */
        }
     } else {
@@ -362,7 +372,7 @@ static int dict_sdbm_sequence(DICT *dict, const int function,
         */
        if (sdbm_error(dict_sdbm->dbm))
            msg_fatal("error seeking %s: %m", dict_sdbm->dict.name);
-       return (1);                             /* no error: eof/not found */
+       status = 1;                             /* no error: eof/not found */
     }
 
     /*
@@ -372,7 +382,7 @@ static int dict_sdbm_sequence(DICT *dict, const int function,
        && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
        msg_fatal("%s: unlock dictionary: %m", dict_sdbm->dict.name);
 
-    return (0);
+    return (status);
 }
 
 /* dict_sdbm_close - disassociate from data base */
index 723a24dcf4a60c20ef17d89374de6378cf8044e1..f20dc6ccf0c342800c66d7c1a7b93ed80f213d2c 100644 (file)
@@ -44,9 +44,7 @@
 
 static const char *dict_static_lookup(DICT *dict, const char *unused_name)
 {
-    dict_errno = 0;
-
-    return (dict->name);
+    DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, dict->name);
 }
 
 /* dict_static_close - close static dictionary */
index 94f93e23dd88933731201b27ff38527d2eb8ac75..1f85b5f10061bc57f068ba566856f5ee8e096a43 100644 (file)
@@ -159,7 +159,7 @@ static const char *dict_tcp_lookup(DICT *dict, const char *key)
     char   *start;
     int     last_ch;
 
-#define RETURN(errval, result) { dict_errno = errval; return (result); }
+#define RETURN(errval, result) { dict->error = errval; return (result); }
 
     if (msg_verbose)
        msg_info("%s: key %s", myname, key);
@@ -286,8 +286,6 @@ DICT   *dict_tcp_open(const char *map, int open_flags, int dict_flags)
 {
     DICT_TCP *dict_tcp;
 
-    dict_errno = 0;
-
     /*
      * Sanity checks.
      */
index b2f57dfa900ad4c48fe9b640d5d245d7d3748fea..68165e2fb0a6b87a457ef0bbbed385dca80971a0 100644 (file)
@@ -107,30 +107,28 @@ void    dict_test(int argc, char **argv)
                vstream_printf("%s: deleted\n", key);
        } else if (strcmp(cmd, "get") == 0 && key && !value) {
            if ((value = dict_get(dict, key)) == 0) {
-               vstream_printf("%s: %s\n", key, dict_errno ?
+               vstream_printf("%s: %s\n", key, dict->error ?
                               "error" : "not found");
            } else {
                vstream_printf("%s=%s\n", key, value);
            }
        } else if (strcmp(cmd, "put") == 0 && key && value) {
-           /* XXX dict_put returns void, so dict_memcache sets dict_errno. */
-           dict_errno = 0;
-           dict_put(dict, key, value);
-           if (dict_errno)
-               vstream_printf("%s: error\n", key);
+           if (dict_put(dict, key, value) != 0)
+               vstream_printf("%s: %s\n", key, dict->error ?
+                              "error" : "not updated");
            else
                vstream_printf("%s=%s\n", key, value);
        } else if (strcmp(cmd, "first") == 0 && !key && !value) {
            if (dict_seq(dict, DICT_SEQ_FUN_FIRST, &key, &value) == 0)
                vstream_printf("%s=%s\n", key, value);
            else
-               vstream_printf("%s\n", dict_errno ?
+               vstream_printf("%s\n", dict->error ?
                               "error" : "not found");
        } else if (strcmp(cmd, "next") == 0 && !key && !value) {
            if (dict_seq(dict, DICT_SEQ_FUN_NEXT, &key, &value) == 0)
                vstream_printf("%s=%s\n", key, value);
            else
-               vstream_printf("%s\n", dict_errno ?
+               vstream_printf("%s\n", dict->error ?
                               "error" : "not found");
        } else if (strcmp(cmd, "flags") == 0 && !key && !value) {
            vstream_printf("dict flags %s\n",
index 9099a28789a75d0a66dd68d0c17a9782a7c2d6cc..a03dc3f4bf89b5c9dc232deb64d59f019a95b20c 100644 (file)
@@ -57,7 +57,7 @@ typedef struct {
     HTABLE *table;                     /* in-memory hash */
     HTABLE_INFO **info;                        /* for iterator */
     HTABLE_INFO **cursor;              /* ditto */
-}       DICT_THASH;
+} DICT_THASH;
 
 #define STR    vstring_str
 
@@ -68,8 +68,6 @@ static const char *dict_thash_lookup(DICT *dict, const char *name)
     DICT_THASH *dict_thash = (DICT_THASH *) dict;
     const char *result = 0;
 
-    dict_errno = 0;
-
     /*
      * Optionally fold the key.
      */
@@ -85,7 +83,7 @@ static const char *dict_thash_lookup(DICT *dict, const char *name)
      */
     result = htable_find(dict_thash->table, name);
 
-    return (result);
+    DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, result);
 }
 
 /* dict_thash_sequence - traverse the dictionary */
@@ -96,8 +94,6 @@ static int dict_thash_sequence(DICT *dict, int function,
     const char *myname = "dict_thash_sequence";
     DICT_THASH *dict_thash = (DICT_THASH *) dict;
 
-    dict_errno = 0;
-
     /*
      * Determine and execute the seek function.
      */
@@ -121,9 +117,11 @@ static int dict_thash_sequence(DICT *dict, int function,
     if (dict_thash->cursor[0]) {
        *key = dict_thash->cursor[0]->key;
        *value = dict_thash->cursor[0]->value;
-       return (0);
+       DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_SUCCESS);
     } else {
-       return (1);
+       *key = 0;
+       *value = 0;
+       DICT_ERR_VAL_RETURN(dict, DICT_ERR_NONE, DICT_STAT_FAIL);
     }
 }
 
index 66baba8eb1758aff3b04316f6ac624a9e5c2d613..cd103cb40aca8d427874f149cd6fa95118e52eec 100644 (file)
@@ -69,7 +69,7 @@ static const char *dict_unix_getpwnam(DICT *dict, const char *key)
     static VSTRING *buf;
     static int sanity_checked;
 
-    dict_errno = 0;
+    dict->error = 0;
 
     /*
      * Optionally fold the key.
@@ -86,7 +86,7 @@ static const char *dict_unix_getpwnam(DICT *dict, const char *key)
            errno = 0;
            if (getpwuid(0) == 0) {
                msg_warn("cannot access UNIX password database: %m");
-               dict_errno = DICT_ERR_RETRY;
+               dict->error = DICT_ERR_RETRY;
            }
        }
        return (0);
@@ -111,7 +111,7 @@ static const char *dict_unix_getgrnam(DICT *dict, const char *key)
     char  **cpp;
     static int sanity_checked;
 
-    dict_errno = 0;
+    dict->error = 0;
 
     /*
      * Optionally fold the key.
@@ -128,7 +128,7 @@ static const char *dict_unix_getgrnam(DICT *dict, const char *key)
            errno = 0;
            if (getgrgid(0) == 0) {
                msg_warn("cannot access UNIX group database: %m");
-               dict_errno = DICT_ERR_RETRY;
+               dict->error = DICT_ERR_RETRY;
            }
        }
        return (0);
@@ -173,8 +173,6 @@ DICT   *dict_unix_open(const char *map, int unused_flags, int dict_flags)
     };
     struct dict_unix_lookup *lp;
 
-    dict_errno = 0;
-
     dict_unix = (DICT_UNIX *) dict_alloc(DICT_TYPE_UNIX, map,
                                         sizeof(*dict_unix));
     for (lp = dict_unix_lookup; /* void */ ; lp++) {
index ebc13886fd71a8f37304387ec86931e514fdb052..c15f995aa5355c4251151c4eaef96ffa02671e84 100644 (file)
@@ -36,8 +36,9 @@
 /*     foo.com. If this flag is cleared, foo.com matches itself
 /*     only, and .foo.com matches any name below the domain foo.com.
 /* .IP MATCH_FLAG_RETURN
-/*     Request that match_list_match() returns zero (with dict_errno
-/*     set) instead of raising a fatal run-time error.
+/*     Request that match_list_match() logs a warning and returns
+/*     zero (with list->error set to a non-zero dictionary error
+/*     code) instead of raising a fatal run-time error.
 /* .RE
 /*     Specify MATCH_FLAG_NONE to request none of the above.
 /*     The pattern_list argument specifies a list of patterns.  The third
@@ -51,7 +52,7 @@
 /*     match_list_free() releases storage allocated by match_list_init().
 /* DIAGNOSTICS
 /*     Fatal error: unable to open or read a match_list file; invalid
-/*     match_list pattern.
+/*     match_list pattern. 
 /* SEE ALSO
 /*     host_match(3) match hosts by name or by address
 /* LICENSE
 #include <stringops.h>
 #include <argv.h>
 #include <dict.h>
-#include <match_ops.h>
 #include <match_list.h>
 
 /* Application-specific */
 
-struct MATCH_LIST {
-    int     flags;                     /* processing options */
-    ARGV   *patterns;                  /* one pattern each */
-    int     match_count;               /* match function/argument count */
-    MATCH_LIST_FN *match_func;         /* match functions */
-    const char **match_args;           /* match arguments */
-};
-
 #define MATCH_DICTIONARY(pattern) \
     ((pattern)[0] != '[' && strchr((pattern), ':') != 0)
 
@@ -209,14 +201,14 @@ int     match_list_match(MATCH_LIST *list,...)
        list->match_args[i] = va_arg(ap, const char *);
     va_end(ap);
 
-    dict_errno = 0;
+    list->error = 0;
     for (cpp = list->patterns->argv; (pat = *cpp) != 0; cpp++) {
        for (match = 1; *pat == '!'; pat++)
            match = !match;
        for (i = 0; i < list->match_count; i++)
-           if (list->match_func[i] (list->flags, list->match_args[i], pat))
+           if (list->match_func[i] (list, list->match_args[i], pat))
                return (match);
-           else if (dict_errno != 0)
+           else if (list->error != 0)
                return (0);
     }
     if (msg_verbose)
index cbbc71a36848c9050f736ec7c5adf9e20146a00d..d51b6e831f50916c0af362efeea8731cdd782e93 100644 (file)
  /*
   * Utility library.
   */
-#include <match_ops.h>
+#include <argv.h>
 
  /*
   * External interface.
   */
 typedef struct MATCH_LIST MATCH_LIST;
-typedef int (*MATCH_LIST_FN) (int, const char *, const char *);
+
+typedef int (*MATCH_LIST_FN) (MATCH_LIST *, const char *, const char *);
+
+struct MATCH_LIST {
+    int     flags;                     /* processing options */
+    ARGV   *patterns;                  /* one pattern each */
+    int     match_count;               /* match function/argument count */
+    MATCH_LIST_FN *match_func;         /* match functions */
+    const char **match_args;           /* match arguments */
+    int     error;                     /* last operation */
+};
+
+#define MATCH_FLAG_NONE                0
+#define MATCH_FLAG_PARENT      (1<<0)
+#define MATCH_FLAG_RETURN      (1<<1)
+#define MATCH_FLAG_ALL         (MATCH_FLAG_PARENT | MATCH_FLAG_RETURN)
 
 extern MATCH_LIST *match_list_init(int, const char *, int,...);
 extern int match_list_match(MATCH_LIST *,...);
 extern void match_list_free(MATCH_LIST *);
 
+ /*
+  * The following functions are not part of the public interface. These
+  * functions may be called only through match_list_match().
+  */
+extern int match_string(MATCH_LIST *, const char *, const char *);
+extern int match_hostname(MATCH_LIST *, const char *, const char *);
+extern int match_hostaddr(MATCH_LIST *, const char *, const char *);
+
 /* LICENSE
 /* .ad
 /* .fi
@@ -38,3 +61,4 @@ extern void match_list_free(MATCH_LIST *);
 /*--*/
 
 #endif
+
index 62aa77ab5bf1a0ad83b3a9606d8dc39d979ba8cd..d138d05799ed6ae90aba59744d40502504036e53 100644 (file)
@@ -4,20 +4,20 @@
 /* SUMMARY
 /*     simple string or host pattern matching
 /* SYNOPSIS
-/*     #include <match_ops.h>
+/*     #include <match_list.h>
 /*
-/*     int     match_string(flags, string, pattern)
-/*     int     flags;
+/*     int     match_string(list, string, pattern)
+/*     MATCH_LIST *list;
 /*     const char *string;
 /*     const char *pattern;
 /*
-/*     int     match_hostname(flags, name, pattern)
-/*     int     flags;
+/*     int     match_hostname(list, name, pattern)
+/*     MATCH_LIST *list;
 /*     const char *name;
 /*     const char *pattern;
 /*
-/*     int     match_hostaddr(flags, addr, pattern)
-/*     int     flags;
+/*     int     match_hostaddr(list, addr, pattern)
+/*     MATCH_LIST *list;
 /*     const char *addr;
 /*     const char *pattern;
 /* DESCRIPTION
@@ -38,8 +38,9 @@
 /*     the domain foo.com. If this flag is cleared, foo.com matches itself
 /*     only, and .foo.com matches any name below the domain foo.com.
 /* .IP MATCH_FLAG_RETURN
-/*     Return "not found" and set dict_errno, instead of raising
-/*     a fatal run-time error.
+/*     Log a warning, return "not found", and set list->error to
+/*     a non-zero dictionary error code, instead of raising a fatal
+/*     run-time error.
 /* .RE
 /*     Specify MATCH_FLAG_NONE to request none of the above.
 /*
@@ -77,7 +78,7 @@
 #include <mymalloc.h>
 #include <split_at.h>
 #include <dict.h>
-#include <match_ops.h>
+#include <match_list.h>
 #include <stringops.h>
 #include <cidr_match.h>
 
@@ -86,7 +87,7 @@
 
 /* match_error - return or raise fatal error */
 
-static int match_error(int flags, const char *fmt,...)
+static int match_error(MATCH_LIST *list, const char *fmt,...)
 {
     VSTRING *buf = vstring_alloc(100);
     va_list ap;
@@ -97,7 +98,7 @@ static int match_error(int flags, const char *fmt,...)
     va_start(ap, fmt);
     vstring_vsprintf(buf, fmt, ap);
     va_end(ap);
-    if (flags & MATCH_FLAG_RETURN) {
+    if (list->flags & MATCH_FLAG_RETURN) {
        msg_warn("%s", vstring_str(buf));
     } else {
        msg_fatal("%s", vstring_str(buf));
@@ -108,7 +109,7 @@ static int match_error(int flags, const char *fmt,...)
 
 /* match_string - match a string literal */
 
-int     match_string(int flags, const char *string, const char *pattern)
+int     match_string(MATCH_LIST *list, const char *string, const char *pattern)
 {
     const char *myname = "match_string";
     DICT   *dict;
@@ -124,8 +125,8 @@ int     match_string(int flags, const char *string, const char *pattern)
            msg_panic("%s: unknown dictionary: %s", myname, pattern);
        if (dict_get(dict, string) != 0)
            return (1);
-       if (dict_errno != 0)
-           return (match_error(flags, "%s:%s: table lookup problem",
+       if ((list->error = dict->error) != 0)
+           return (match_error(list, "%s:%s: table lookup problem",
                                dict->type, dict->name));
        return (0);
     }
@@ -145,7 +146,7 @@ int     match_string(int flags, const char *string, const char *pattern)
 
 /* match_hostname - match a host by name */
 
-int     match_hostname(int flags, const char *name, const char *pattern)
+int     match_hostname(MATCH_LIST *list, const char *name, const char *pattern)
 {
     const char *myname = "match_hostname";
     const char *pd;
@@ -175,13 +176,13 @@ int     match_hostname(int flags, const char *name, const char *pattern)
                             match ? "found" : "notfound");
                if (match != 0)
                    break;
-               if (dict_errno != 0)
-                   return (match_error(flags, "%s:%s: table lookup problem",
+               if ((list->error = dict->error) != 0)
+                   return (match_error(list, "%s:%s: table lookup problem",
                                        dict->type, dict->name));
            }
            if ((next = strchr(entry + 1, '.')) == 0)
                break;
-           if (flags & MATCH_FLAG_PARENT)
+           if (list->flags & MATCH_FLAG_PARENT)
                next += 1;
        }
        return (match);
@@ -198,7 +199,7 @@ int     match_hostname(int flags, const char *name, const char *pattern)
      * See if the pattern is a parent domain of the hostname.
      */
     else {
-       if (flags & MATCH_FLAG_PARENT) {
+       if (list->flags & MATCH_FLAG_PARENT) {
            pd = name + strlen(name) - strlen(pattern);
            if (pd > name && pd[-1] == '.' && strcasecmp(pd, pattern) == 0)
                return (1);
@@ -213,7 +214,7 @@ int     match_hostname(int flags, const char *name, const char *pattern)
 
 /* match_hostaddr - match host by address */
 
-int     match_hostaddr(int flags, const char *addr, const char *pattern)
+int     match_hostaddr(MATCH_LIST *list, const char *addr, const char *pattern)
 {
     const char *myname = "match_hostaddr";
     char   *saved_patt;
@@ -239,8 +240,8 @@ int     match_hostaddr(int flags, const char *addr, const char *pattern)
            msg_panic("%s: unknown dictionary: %s", myname, pattern);
        if (dict_get(dict, addr) != 0)
            return (1);
-       if (dict_errno != 0)
-           return (match_error(flags, "%s:%s: table lookup problem",
+       if ((list->error = dict->error) != 0)
+           return (match_error(list, "%s:%s: table lookup problem",
                                dict->type, dict->name));
        return (0);
     }
@@ -296,8 +297,8 @@ int     match_hostaddr(int flags, const char *addr, const char *pattern)
     err = cidr_match_parse(&match_info, saved_patt, (VSTRING *) 0);
     myfree(saved_patt);
     if (err != 0) {
-       dict_errno = DICT_ERR_CONFIG;
-       rc = match_error(flags, "%s", vstring_str(err));
+       list->error = DICT_ERR_CONFIG;
+       rc = match_error(list, "%s", vstring_str(err));
        vstring_free(err);
        return (rc);
     }
diff --git a/postfix/src/util/match_ops.h b/postfix/src/util/match_ops.h
deleted file mode 100644 (file)
index 055c4f7..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef _MATCH_OPS_H_INCLUDED_
-#define _MATCH_OPS_H_INCLUDED_
-
-/*++
-/* NAME
-/*     match_ops 3h
-/* SUMMARY
-/*     simple string or host pattern matching
-/* SYNOPSIS
-/*     #include <match_ops.h>
-/* DESCRIPTION
-/* .nf
-
- /*
-  * Utility library.
-  */
-#include <dict.h>
-
- /*
-  * External interface.
-  */
-#define MATCH_FLAG_NONE                0
-#define MATCH_FLAG_PARENT      (1<<0)
-#define MATCH_FLAG_RETURN      (1<<1)
-#define MATCH_FLAG_ALL         (MATCH_FLAG_PARENT | MATCH_FLAG_RETURN)
-
-extern int match_string(int, const char *, const char *);
-extern int match_hostname(int, const char *, const char *);
-extern int match_hostaddr(int, const char *, const char *);
-
-/* 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
-/*--*/
-
-#endif
index 42198a2a71b899a25a22cdd92dbc7932df774709..4b1c6d0bf397c92d955a823157514e41630cd5fe 100644 (file)
 /* DESCRIPTION
 /*     .nf
 
+/*
+ * System library.
+ */
+#include <time.h>
+
 /*
  * External interface.
  */
@@ -29,6 +34,10 @@ extern int msg_error_limit(int);
 extern void msg_error_clear(void);
 extern MSG_CLEANUP_FN msg_cleanup(MSG_CLEANUP_FN);
 
+extern void PRINTFLIKE(4, 5) msg_rate_delay(time_t *, int,
+                                         void (*log_fn) (const char *,...),
+                                                   const char *,...);
+
 /* LICENSE
 /* .ad
 /* .fi
diff --git a/postfix/src/util/msg_rate_delay.c b/postfix/src/util/msg_rate_delay.c
new file mode 100644 (file)
index 0000000..e21b021
--- /dev/null
@@ -0,0 +1,138 @@
+/*++
+/* NAME
+/*     msg_rate_delay 3
+/* SUMMARY
+/*     diagnostic interface
+/* SYNOPSIS
+/*     #include <msg.h>
+/*
+/*     void    msg_rate_delay(stamp, delay, log_fn, fmt, ...)
+/*     time_t  *stamp;
+/*     int     delay;
+/*     void    (*log_fn)(const char *fmt, ...);
+/*     const char *fmt;
+/* DESCRIPTION
+/*     msg_rate_delay() produces log output at a reduced rate: no
+/*     more than one message per 'delay' seconds. It discards log
+/*     output that would violate the output rate policy.
+/*
+/*     This is typically used to log errors accessing a cache with
+/*     high-frequency access but low-value information, to avoid
+/*     spamming the logfile with the same kind of message.
+/*
+/*     Arguments:
+/* .IP stamp
+/*     Time stamp of last log output; specify a zero time stamp
+/*     on the first call.  This is an input-output parameter.
+/*     This parameter is ignored when verbose logging is enabled
+/*     or when the delay value is zero.
+/* .IP delay
+/*     The minimum time between log outputs; specify zero to log
+/*     all output for debugging purposes.  This parameter is ignored
+/*     when verbose logging is enabled.
+/* .IP log_fn
+/*     The function that produces log output. Typically, this will
+/*     be msg_info() or msg_warn().
+/* .IP fmt
+/*     Format string as used with msg(3) routines.
+/* SEE ALSO
+/*     msg(3) diagnostics interface
+/* DIAGNOSTICS
+/*     Fatal errors: memory allocation problem.
+/* 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 <time.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstring.h>
+#include <events.h>
+
+/* SLMs. */
+
+#define STR(x) vstring_str(x)
+
+/* msg_rate_delay - rate-limit message logging */
+
+void    msg_rate_delay(time_t *stamp, int delay,
+                              void (*log_fn) (const char *,...),
+                              const char *fmt,...)
+{
+    const char *myname = "msg_rate_delay";
+    static time_t saved_event_time;
+    time_t  now;
+    VSTRING *buf;
+    va_list ap;
+
+    /*
+     * Sanity check.
+     */
+    if (delay < 0)
+       msg_panic("%s: bad message rate delay: %d", myname, delay);
+
+    /*
+     * This function may be called frequently. Avoid an unnecessary syscall
+     * if possible. Deal with the possibility that a program does not use the
+     * events(3) engine, so that event_time() always produces the same
+     * result.
+     */
+    if (msg_verbose == 0 && delay > 0) {
+       if (saved_event_time == 0)
+           now = saved_event_time = event_time();
+       else if ((now = event_time()) == saved_event_time)
+           now = time((time_t *) 0);
+
+       /*
+        * Don't log if time is too early.
+        */
+       if (*stamp + delay > now)
+           return;
+       *stamp = now;
+    }
+
+    /*
+     * OK to log. This is a low-rate event, so we can afford some overhead.
+     */
+    buf = vstring_alloc(100);
+    va_start(ap, fmt);
+    vstring_vsprintf(buf, fmt, ap);
+    va_end(ap);
+    log_fn("%s", STR(buf));
+    vstring_free(buf);
+}
+
+#ifdef TEST
+
+ /*
+  * Proof-of-concept test program: log messages but skip messages during a
+  * two-second gap.
+  */
+#include <unistd.h>
+
+int     main(int argc, char **argv)
+{
+    int     n;
+    time_t  stamp = 0;
+
+    for (n = 0; n < 6; n++) {
+       msg_rate_delay(&stamp, 2, msg_info, "text here %d", n);
+       sleep(1);
+    }
+    return (0);
+}
+
+#endif
index f0ad6eb4a2640d7d9a4028e06dc1a2e2b259aa38..e04c42682c1208de33662a48c11dc98b8f04fa0f 100644 (file)
@@ -195,7 +195,7 @@ int     deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
     mailbox_res = mail_addr_find(virtual_mailbox_maps, state.msg_attr.user,
                                 IGNORE_EXTENSION);
     if (mailbox_res == 0) {
-       if (dict_errno == 0)
+       if (virtual_mailbox_maps->error == 0)
            return (NO);
        msg_warn("table %s: lookup %s: %m", virtual_mailbox_maps->title,
                 state.msg_attr.user);