]> git.pld-linux.org Git - packages/postfix.git/commitdiff
- PostgreSQL maps support (from Konrad Rzentarzewski)
authorJakub Bogusz <qboosh@pld-linux.org>
Thu, 14 Mar 2002 13:20:56 +0000 (13:20 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    postfix-pgsql.patch -> 1.1

postfix-pgsql.patch [new file with mode: 0644]

diff --git a/postfix-pgsql.patch b/postfix-pgsql.patch
new file mode 100644 (file)
index 0000000..2b05254
--- /dev/null
@@ -0,0 +1,921 @@
+diff -rU3 --new-file postfix-1.1.3-vanilla/PGSQL_README postfix-1.1.3/PGSQL_README
+--- postfix-1.1.3-vanilla/PGSQL_README Thu Jan  1 01:00:00 1970
++++ postfix-1.1.3/PGSQL_README Thu Mar  7 11:48:40 2002
+@@ -0,0 +1,88 @@
++[Code contributed by Mathieu Arnold]
++
++We've written code to add a pgsql map type.  It utilizes the pgsql 
++client library, which can be obtained from:
++
++                 http://www.postgresql.org/
++
++In order to build postfix with pgsql map support, you will need to add 
++-DHAS_PGSQL and -I for the directory containing the postgres headers, and 
++the libpq library (and libcrypt) to AUXLIBS, for example:
++
++make -f Makefile.init makefiles \
++      'CCARGS=-DHAS_PGSQL -I/some/where/include/postgresql' \
++      'AUXLIBS=/some/where/lib/postgres/libpq.a -lcrypt'
++
++then, just run 'make'.
++
++Postfix installations which may benefit from using pgsql map types
++include sites that have a need for instantaneous updates of
++forwarding, and sites that may benefit from having mail exchangers
++reference a networked database, possibly working in conjunction with a
++customer database of sorts.
++
++Once postfix is built with pgsql support, you can specify a map type
++in main.cf like this:
++
++alias_maps = pgsql:/etc/postfix/pgsql-aliases.cf
++
++The file /etc/postfix/pgsql-aliases.cf specifies lots of information
++telling postfix how to reference the postgresql database.  An example
++postgresql map config file follows:
++
++#
++# postgresql config file for alias lookups on postfix
++# comments are ok.
++#
++
++# the user name and password to log into the pgsql server
++user = someone
++password = some_passwordd 
++
++# the database name on the servers
++dbname = customer_database
++
++# the table name
++table = mxaliases
++
++#
++select_field = forw_addr
++where_field = alias
++
++# you may specify additional_conditions here
++additional_conditions = and status = 'paid'
++
++# the above variables will result in a query of
++# the form: 
++# select forw_addr from mxaliases where alias = '$lookup' and status = 'paid'
++# ($lookup is escaped so if it contains single quotes or other odd
++# characters, it will not cause a parse error in the sql).
++#
++# the hosts that postfix will try to connect to
++# and query from (in the order listed)
++hosts = host1.some.domain host2.some.domain
++
++# end postgresql config file
++
++Some notes:
++
++This configuration interface setup allows for multiple postgresql
++databases: you can use one for a virtual table, one for an access
++table, and one for an aliases table if you want.
++
++Since sites that have a need for multiple mail exchangers may enjoy
++the convenience of using a networked mailer database, but do not want 
++to introduce a single point of failure to their system, we've included 
++the ability to have postfix reference multiple hosts for access to a
++single pgsql map.  This will work if sites set up mirrored pgsql
++databases on two or more hosts.  Whenever queries fail with an error
++at one host, the rest of the hosts will be tried in order.  Each host
++that is in an error state will undergo a reconnection attempt every so 
++often, and if no pgsql server hosts are reachable, then mail will be
++deferred until atleast one of those hosts is reachable.
++
++Performance of postfix with pgsql has not been thoroughly tested,
++however, we have found it to be stable.  Busy mail servers using pgsql
++maps will generate lots of concurrent pgsql clients, so the pgsql
++server(s) should be run with this fact in mind.  Any further
++performance information, in addition to any feedback is most welcome.
+diff -rU3 --new-file postfix-1.1.3-vanilla/src/util/Makefile.in postfix-1.1.3/src/util/Makefile.in
+--- postfix-1.1.3-vanilla/src/util/Makefile.in Thu Mar  7 11:47:44 2002
++++ postfix-1.1.3/src/util/Makefile.in Thu Mar  7 12:10:56 2002
+@@ -4,7 +4,7 @@
+       chroot_uid.c clean_env.c close_on_exec.c concatenate.c ctable.c \
+       dict.c dict_alloc.c dict_db.c dict_dbm.c dict_debug.c dict_env.c \
+       dict_ht.c dict_mysql.c dict_ni.c dict_nis.c \
+-      dict_nisplus.c dict_open.c dict_pcre.c dict_regexp.c dict_static.c \
++      dict_nisplus.c dict_open.c dict_pcre.c dict_pgsql.c dict_regexp.c dict_static.c \
+       dict_tcp.c dict_unix.c dir_forest.c doze.c duplex_pipe.c \
+       environ.c events.c exec_command.c fifo_listen.c fifo_trigger.c \
+       file_limit.c find_inet.c fsspace.c fullname.c get_domainname.c \
+@@ -58,7 +58,7 @@
+ HDRS  = argv.h attr.h base64_code.h binhash.h chroot_uid.h clean_env.h \
+       connect.h ctable.h dict.h dict_db.h dict_dbm.h dict_env.h \
+       dict_ht.h dict_ldap.h dict_mysql.h dict_ni.h dict_nis.h \
+-      dict_nisplus.h dict_pcre.h dict_regexp.h dict_static.h dict_tcp.h \
++      dict_nisplus.h dict_pcre.h dict_pgsql.h dict_regexp.h dict_static.h dict_tcp.h \
+       dict_unix.h dir_forest.h events.h exec_command.h find_inet.h \
+       fsspace.h fullname.h get_domainname.h get_hostname.h get_port.h hex_quote.h \
+       htable.h inet_addr_host.h inet_addr_list.h inet_addr_local.h \
+@@ -84,6 +84,7 @@
+ INCL  =
+ PCRESO  = dict_pcre.so
+ MYSQLSO = dict_mysql.so
++PGSQLSO = dict_pgsql.so
+ LIB   = libutil.a
+ TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \
+       fifo_rdonly_bug fifo_rdwr_bug fifo_trigger fsspace fullname \
+@@ -96,7 +97,7 @@
+ LIB_DIR       = ../../lib
+ INC_DIR       = ../../include
+-LIBS    = $(LIB_DIR)/$(LIB) $(LIB_DIR)/$(PCRESO) $(LIB_DIR)/$(MYSQLSO)
++LIBS    = $(LIB_DIR)/$(LIB) $(LIB_DIR)/$(PCRESO) $(LIB_DIR)/$(MYSQLSO) $(LIB_DIR)/$(PGSQLSO)
+ .c.o:;        $(CC) -fPIC $(CFLAGS) -c $*.c
+@@ -113,6 +114,9 @@
+ $(MYSQLSO): dict_mysql.o
+       gcc -shared -Wl,-soname,dict_mysql.so -o $@ $? -lmysqlclient -L. -lutil
++$(PGSQLSO): dict_pgsql.o
++      gcc -shared -Wl,-soname,dict_pgsql.so -o $@ $? -lpq -lcrypt -L. -lutil
++
+ $(LIB):       $(OBJS)
+       gcc -shared -Wl,-soname,libpostfix-util.so.1 -o $(LIB) $(OBJS) -ldl
+@@ -125,6 +129,9 @@
+ $(LIB_DIR)/$(MYSQLSO): $(MYSQLSO)
+       cp $(MYSQLSO) $(LIB_DIR)
++$(LIB_DIR)/$(PGSQLSO): $(PGSQLSO)
++      cp $(PGSQLSO) $(LIB_DIR)
++
+ update: $(LIBS) $(HDRS)
+       -for i in $(HDRS); \
+       do \
+@@ -147,7 +154,7 @@
+       lint $(SRCS)
+ clean:
+-      rm -f *.o $(LIB) $(PCRESO) $(MYSQLSO) *core $(TESTPROG) \
++      rm -f *.o $(LIB) $(PCRESO) $(MYSQLSO) $(PGSQLSO) *core $(TESTPROG) \
+               junk $(MAKES) *.tmp
+       rm -rf printfck
+@@ -571,6 +578,8 @@
+ dict_ldap.o: sys_defs.h
+ dict_mysql.o: dict_mysql.c
+ dict_mysql.o: sys_defs.h
++dict_pgsql.o: dict_pgsql.c
++dict_pgsql.o: sys_defs.h
+ dict_ni.o: dict_ni.c
+ dict_ni.o: sys_defs.h
+ dict_nis.o: dict_nis.c
+@@ -612,6 +621,7 @@
+ dict_open.o: dict_ni.h
+ dict_open.o: dict_ldap.h
+ dict_open.o: dict_mysql.h
++dict_open.o: dict_pgsql.h
+ dict_open.o: dict_pcre.h
+ dict_open.o: dict_regexp.h
+ dict_open.o: dict_static.h
+diff -rU3 --new-file postfix-1.1.3-vanilla/src/util/dict_open.c postfix-1.1.3/src/util/dict_open.c
+--- postfix-1.1.3-vanilla/src/util/dict_open.c Thu Mar  7 11:47:44 2002
++++ postfix-1.1.3/src/util/dict_open.c Thu Mar  7 11:48:40 2002
+@@ -170,6 +170,7 @@
+ #include <dict_ni.h>
+ #include <dict_ldap.h>
+ #include <dict_mysql.h>
++#include <dict_pgsql.h>
+ #include <dict_pcre.h>
+ #include <dict_regexp.h>
+ #include <dict_static.h>
+@@ -223,6 +224,9 @@
+ #ifdef HAS_MYSQL
+     DICT_TYPE_MYSQL, dict_mysql_open,
+ #endif
++#ifdef HAS_PGSQL
++    DICT_TYPE_PGSQL, dict_pgsql_open,
++#endif
+ #ifdef HAS_PCRE
+     DICT_TYPE_PCRE, dict_pcre_open,
+ #endif
+diff -rU3 --new-file postfix-1.1.3-vanilla/src/util/dict_pgsql.c postfix-1.1.3/src/util/dict_pgsql.c
+--- postfix-1.1.3-vanilla/src/util/dict_pgsql.c        Thu Jan  1 01:00:00 1970
++++ postfix-1.1.3/src/util/dict_pgsql.c        Thu Mar  7 11:48:41 2002
+@@ -0,0 +1,675 @@
++
++/*++
++/* NAME
++/*    dict_pgsql 3
++/* SUMMARY
++/*    dictionary manager interface to db files
++/* SYNOPSIS
++/*    #include <dict.h>
++/*    #include <dict_pgsql.h>
++/*
++/*    DICT    *dict_pgsql_open(name, dummy, unused_dict_flags)
++/*    const char      *name;
++/*    int     dummy;
++/*    int     unused_dict_flags;
++/* DESCRIPTION
++/*    dict_pgsql_open() creates a dictionary of type 'pg'.  This
++/*    dictionary is an interface for the postfix key->value mappings
++/*    to pgsql.  The result is a pointer to the installed dictionary,
++/*    or a null pointer in case of problems.
++/*
++/*    The pgsql dictionary can manage multiple connections to different
++/*    sql servers on different hosts.  It assumes that the underlying data
++/*    on each host is identical (mirrored) and maintains one connection
++/*    at any given time.  If any connection fails,  any other available
++/*    ones will be opened and used.  The intent of this feature is to eliminate
++/*    a single point of failure for mail systems that would otherwise rely
++/*    on a single pgsql server.
++/*
++/*    Arguments:
++/* .IP name
++/*    The path of the PostgreSQL configuration file.  The file encodes a number of
++/*    pieces of information: username, password, databasename, table,
++/*    select_field, where_field, and hosts.  For example, if you want the map to
++/*    reference databases of the name "your_db" and execute a query like this:
++/*    select forw_addr from aliases where alias like '<some username>' against
++/*    any database called "vmailer_info" located on hosts host1.some.domain and
++/*    host2.some.domain, logging in as user "vmailer" and password "passwd" then
++/*    the configuration file should read:
++/*
++/*    user = vmailer
++/*    password = passwd
++/*    DBname = vmailer_info
++/*    table = aliases
++/*    select_field = forw_addr
++/*    where_field = alias
++/*    hosts = host1.some.domain host2.some.domain
++/*
++/* .IP other_name
++/*    reference for outside use.
++/* .IP unusued_flags
++/*    unused flags
++/* SEE ALSO
++/*    dict(3) generic dictionary manager
++/* AUTHOR(S)
++/*      Mathieu Arnold
++/*      Absolight
++/*      mat@absolight.com
++/*      
++/*      based on dict_mysql by
++/*      
++/*    Scott Cotton
++/*    IC Group, Inc.
++/*    scott@icgroup.com
++/*
++/*    Joshua Marcus
++/*    IC Group, Inc.
++/*    josh@icgroup.com
++/*--*/
++
++/* System library. */
++#include "sys_defs.h"
++
++#ifdef HAS_PGSQL
++#include <sys/socket.h>
++#include <netinet/in.h>
++#include <arpa/inet.h>
++#include <netdb.h>
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++#include <syslog.h>
++#include <time.h>
++#include <libpq-fe.h>
++
++/* Utility library. */
++#include "dict.h"
++#include "msg.h"
++#include "mymalloc.h"
++#include "dict_pgsql.h"
++#include "argv.h"
++#include "vstring.h"
++#include "split_at.h"
++#include "find_inet.h"
++
++/* need some structs to help organize things */
++typedef struct
++{
++    PGconn *db;
++    char   *hostname;
++    int     stat;                     /* STATUNTRIED | STATFAIL | STATCUR */
++    time_t  ts;                               /* used for attempting reconnection
++                                       * every so often if a host is down */
++} HOST;
++
++typedef struct
++{
++    int     len_hosts;                        /* number of hosts */
++    HOST   *db_hosts;                 /* the hosts on which the databases
++                                       * reside */
++} PLPGSQL;
++
++typedef struct
++{
++    char   *username;
++    char   *password;
++    char   *dbname;
++    char   *table;
++    char   *select_field;
++    char   *where_field;
++    char   *additional_conditions;
++    char  **hostnames;
++    int     len_hosts;
++} PGSQL_NAME;
++
++typedef struct
++{
++    DICT    dict;
++    PLPGSQL *pldb;
++    PGSQL_NAME *name;
++} DICT_PGSQL;
++
++#define STATACTIVE 0
++#define STATFAIL 1
++#define STATUNTRIED 2
++#define RETRY_CONN_INTV 60                    /* 1 minute */
++
++/* internal function declarations */
++static PLPGSQL *plpgsql_init (char *hostnames[], int);
++static PGresult *plpgsql_query (PLPGSQL *, const char *, char *, char *,
++
++                              char *);
++static void plpgsql_dealloc (PLPGSQL *);
++static void plpgsql_down_host (HOST *);
++static void plpgsql_connect_single (HOST *, char *, char *, char *);
++static int plpgsql_ready_reconn (HOST *);
++static const char *dict_pgsql_lookup (DICT *, const char *);
++DICT   *dict_pgsql_open (const char *, int, int);
++static void dict_pgsql_close (DICT *);
++static PGSQL_NAME *pgsqlname_parse (const char *);
++static HOST host_init (char *);
++void    pgsql_escape_string (char *escaped, const char *name, int len);
++
++
++
++/**********************************************************************
++ * public interface dict_pgsql_lookup
++ * find database entry return 0 if no alias found, set dict_errno
++ * on errors to DICT_ERRBO_RETRY and set dict_errno to 0 on success
++ *********************************************************************/
++static const char *dict_pgsql_lookup (DICT *dict, const char *name)
++{
++    PGresult *query_res;
++    char   *field;
++    DICT_PGSQL *dict_pgsql;
++    PLPGSQL *pldb;
++    static VSTRING *result;
++    static VSTRING *query = 0;
++    int     i,
++            j,
++            numrows;
++    char   *name_escaped = 0;
++
++    dict_pgsql = (DICT_PGSQL *) dict;
++    pldb = dict_pgsql->pldb;
++    /* initialization  for query */
++    query = vstring_alloc (24);
++    vstring_strcpy (query, "");
++    if (
++      (name_escaped =
++       (char *) mymalloc ((sizeof (char) * (strlen (name) * 2) + 1))) ==
++      NULL)
++      {
++        msg_fatal ("dict_pgsql_lookup: out of memory.");
++      }
++    /* prepare the query */
++    pgsql_escape_string (name_escaped, name, (unsigned int) strlen (name));
++    vstring_sprintf (query, "select %s from %s where %s = '%s' %s",
++                   dict_pgsql->name->select_field, dict_pgsql->name->table,
++                   dict_pgsql->name->where_field, name_escaped,
++                   dict_pgsql->name->additional_conditions);
++    if (msg_verbose)
++      msg_info ("dict_pgsql_lookup using sql query: %s",
++                vstring_str (query));
++    /* free mem associated with preparing the query */
++    myfree (name_escaped);
++    /* do the query - set dict_errno & cleanup if there's an error */
++    if ((query_res = plpgsql_query (pldb,
++                                  vstring_str (query),
++                                  dict_pgsql->name->dbname,
++                                  dict_pgsql->name->username,
++                                  dict_pgsql->name->password)) == 0)
++      {
++        dict_errno = DICT_ERR_RETRY;
++        vstring_free (query);
++        return 0;
++      }
++    dict_errno = 0;
++    /* free the vstring query */
++    vstring_free (query);
++    numrows = PQntuples (query_res);
++    if (msg_verbose)
++      msg_info ("dict_pgsql_lookup: retrieved %d rows", numrows);
++    if (numrows == 0)
++      {
++        PQclear (query_res);
++        return 0;
++      }
++    if (result == 0)
++      result = vstring_alloc (10);
++    vstring_strcpy (result, "");
++    for (i = 0; i < numrows; i++)
++      {
++        if (i > 0)
++            vstring_strcat (result, ",");
++        for (j = 0; j < PQnfields (query_res); j++)
++          {
++              if (j > 0)
++                  vstring_strcat (result, ",");
++              field = PQgetvalue (query_res, i, j);
++              vstring_strcat (result, field);
++              if (msg_verbose > 1)
++                  msg_info ("dict_pgsql_lookup: retrieved field: %d: %s", j,
++                            field);
++          }
++      }
++    PQclear (query_res);
++    return vstring_str (result);
++}
++
++/*
++ * plpgsql_query - process a PGSQL query.  Return PGresult* on success.
++ *                 On failure, log failure and try other db instances.
++ *                 on failure of all db instances, return 0;
++ *                 close unnecessary active connections
++ */
++
++static PGresult *plpgsql_query (PLPGSQL * PLDB,
++                              const char *query,
++                              char *dbname, char *username, char *password)
++{
++    int     i;
++    HOST   *host;
++    PGresult *res = 0;
++    ExecStatusType status;
++
++    for (i = 0; i < PLDB->len_hosts; i++)
++      {
++        /* can't deal with typing or reading PLDB->db_hosts[i] over & over */
++        host = &(PLDB->db_hosts[i]);
++        if (msg_verbose > 1)
++            msg_info ("dict_pgsql: trying host %s stat %d, last res %p",
++                      host->hostname, host->stat, res);
++
++        /* answer already found */
++        if (res != 0 && host->stat == STATACTIVE)
++          {
++              if (msg_verbose)
++                  msg_info
++                      ("dict_pgsql: closing unnessary connection to %s",
++                       host->hostname);
++              plpgsql_down_host (host);
++          }
++        /* try to connect for the first time if we don't have a result yet */
++        if (res == 0 && host->stat == STATUNTRIED)
++          {
++              if (msg_verbose)
++                  msg_info ("dict_pgsql: attempting to connect to host %s",
++                            host->hostname);
++              plpgsql_connect_single (host, dbname, username, password);
++          }
++
++        /*
++         * try to reconnect if we don't have an answer and the host had a
++         * prob in the past and it's time for it to reconnect
++         */
++        if (res == 0 && host->stat == STATFAIL
++            && host->ts < time ((time_t *) 0))
++          {
++              if (msg_verbose)
++                  msg_info
++                      ("dict_pgsql: attempting to reconnect to host %s",
++                       host->hostname);
++              plpgsql_connect_single (host, dbname, username, password);
++          }
++
++        /*
++         * if we don't have a result and the current host is marked active,
++         * try the query.  If the query fails, mark the host STATFAIL
++         */
++        if (res == 0 && host->stat == STATACTIVE)
++          {
++              res = PQexec (host->db, query);
++              status = PQresultStatus (res);
++              if (res
++                  && (status = PGRES_COMMAND_OK
++                      || status == PGRES_TUPLES_OK))
++                {
++                    if (msg_verbose)
++                        msg_info
++                            ("dict_pgsql: successful query from host %s",
++                             host->hostname);
++                }
++              else
++                {
++                    msg_warn ("%s", PQerrorMessage (host->db));
++                    plpgsql_down_host (host);
++                }
++          }
++      }
++    return res;
++}
++
++/*
++ * plpgsql_connect_single -
++ * used to reconnect to a single database when one is down or none is
++ * connected yet. Log all errors and set the stat field of host accordingly
++ */
++static void
++plpgsql_connect_single (HOST *host, char *dbname, char *username,
++                      char *password)
++{
++    char   *destination = host->hostname;
++    char   *hostname = 0;
++    char   *service;
++    VSTRING *conninfo = vstring_alloc (100);
++    char   *conn;
++    unsigned port = 0;
++
++    /*
++     * Ad-hoc parsing code.  Expect "unix:pathname" or "inet:host:port", where
++     * both "inet:" and ":port" are optional.
++     */
++    if (strncmp (destination, "unix:", 5) == 0)
++      {
++        vstring_sprintf_append (conninfo, "host=%s ", destination + 5);
++      }
++    else
++      {
++        if (strncmp (destination, "inet:", 5) == 0)
++            destination += 5;
++        hostname = mystrdup (destination);
++        if ((service = split_at (hostname, ':')) != 0)
++          {
++              port = ntohs (find_inet_port (service, "tcp"));
++              vstring_sprintf_append (conninfo, "host='%s' port='%d'",
++                                      hostname, port);
++          }
++        else
++          {
++              vstring_sprintf_append (conninfo, "host='%s'", hostname);
++          }
++      }
++
++    vstring_sprintf_append (conninfo, " dbname='%s' user='%s' password='%s'", dbname,
++                          username, password);
++    conn = vstring_export (conninfo);
++
++    host->db = PQconnectdb (conn);
++
++    if ((host->db != NULL) && (PQstatus (host->db) == CONNECTION_OK))
++      {
++        if (msg_verbose)
++            msg_info ("dict_pgsql: successful connection to host %s",
++                      host->hostname);
++        host->stat = STATACTIVE;
++      }
++    else
++      {
++        msg_warn ("%s", PQerrorMessage (host->db));
++        plpgsql_down_host (host);
++      }
++    if (hostname)
++      myfree (hostname);
++    myfree (conn);
++}
++
++/*
++ * plpgsql_down_host - mark a HOST down update ts if marked down
++ * for the first time so that we'll know when to retry the connection
++ */
++static void plpgsql_down_host (HOST *host)
++{
++    if (host->stat != STATFAIL)
++      {
++        host->ts = time ((time_t *) 0) + RETRY_CONN_INTV;
++        host->stat = STATFAIL;
++      }
++    PQfinish (host->db);
++    host->db = 0;
++}
++
++/**********************************************************************
++ * public interface dict_pgsql_open
++ *    create association with database with appropriate values
++ *    parse the map's config file
++ *    allocate memory
++ **********************************************************************/
++DICT   *dict_pgsql_open (const char *name, int unused_open_flags,
++                       int dict_flags)
++{
++    DICT_PGSQL *dict_pgsql;
++    int     connections;
++
++    dict_pgsql = (DICT_PGSQL *) dict_alloc (DICT_TYPE_PGSQL, name,
++                                          sizeof (DICT_PGSQL));
++    dict_pgsql->dict.lookup = dict_pgsql_lookup;
++    dict_pgsql->dict.close = dict_pgsql_close;
++    dict_pgsql->dict.flags = dict_flags | DICT_FLAG_FIXED;
++    dict_pgsql->name = pgsqlname_parse (name);
++    dict_pgsql->pldb = plpgsql_init (dict_pgsql->name->hostnames,
++                                   dict_pgsql->name->len_hosts);
++    if (dict_pgsql->pldb == NULL)
++      msg_fatal ("couldn't intialize pldb!\n");
++    dict_register (name, (DICT *) dict_pgsql);
++    return (DICT_DEBUG (&dict_pgsql->dict));
++}
++
++/* pgsqlname_parse - parse pgsql configuration file */
++static PGSQL_NAME *pgsqlname_parse (const char *pgsqlcf_path)
++{
++    int     i;
++    char   *nameval;
++    char   *hosts;
++    PGSQL_NAME *name = (PGSQL_NAME *) mymalloc (sizeof (PGSQL_NAME));
++    ARGV   *hosts_argv;
++    VSTRING *opt_dict_name;
++
++    /*
++     * setup a dict containing info in the pgsql cf file. the dict has a
++     * name, and a path.  The name must be distinct from the path, or the
++     * dict interface gets confused.  The name must be distinct for two
++     * different paths, or the configuration info will cache across different
++     * pgsql maps, which can be confusing.
++     */
++    opt_dict_name = vstring_alloc (64);
++    vstring_sprintf (opt_dict_name, "pgsql opt dict %s", pgsqlcf_path);
++    dict_load_file (vstring_str (opt_dict_name), pgsqlcf_path);
++    /* pgsql username lookup */
++    if (
++      (nameval =
++       (char *) dict_lookup (vstring_str (opt_dict_name), "user")) == NULL)
++      name->username = mystrdup ("");
++    else
++      name->username = mystrdup (nameval);
++    if (msg_verbose)
++      msg_info ("pgsqlname_parse(): set username to '%s'", name->username);
++    /* password lookup */
++    if (
++      (nameval =
++       (char *) dict_lookup (vstring_str (opt_dict_name),
++                             "password")) == NULL)
++      name->password = mystrdup ("");
++    else
++      name->password = mystrdup (nameval);
++    if (msg_verbose)
++      msg_info ("pgsqlname_parse(): set password to '%s'", name->password);
++
++    /* database name lookup */
++    if (
++      (nameval =
++       (char *) dict_lookup (vstring_str (opt_dict_name),
++                             "dbname")) == NULL)
++
++
++
++      msg_fatal ("%s: pgsql options file does not include database name",
++                 pgsqlcf_path);
++    else
++      name->dbname = mystrdup (nameval);
++    if (msg_verbose)
++      msg_info ("pgsqlname_parse(): set database name to '%s'",
++                name->dbname);
++
++    /* table lookup */
++    if (
++      (nameval =
++       (char *) dict_lookup (vstring_str (opt_dict_name), "table")) == NULL)
++      msg_fatal ("%s: pgsql options file does not include table name",
++                 pgsqlcf_path);
++    else
++      name->table = mystrdup (nameval);
++    if (msg_verbose)
++      msg_info ("pgsqlname_parse(): set table name to '%s'", name->table);
++
++    /* select field lookup */
++    if (
++      (nameval =
++       (char *) dict_lookup (vstring_str (opt_dict_name),
++                             "select_field")) == NULL)
++
++
++
++      msg_fatal ("%s: pgsql options file does not include select field",
++                 pgsqlcf_path);
++    else
++      name->select_field = mystrdup (nameval);
++    if (msg_verbose)
++      msg_info ("pgsqlname_parse(): set select_field to '%s'",
++                name->select_field);
++
++    /* where field lookup */
++    if (
++      (nameval =
++       (char *) dict_lookup (vstring_str (opt_dict_name),
++                             "where_field")) == NULL)
++      msg_fatal ("%s: pgsql options file does not include where field",
++                 pgsqlcf_path);
++    else
++      name->where_field = mystrdup (nameval);
++    if (msg_verbose)
++      msg_info ("pgsqlname_parse(): set where_field to '%s'",
++                name->where_field);
++
++    /* additional conditions */
++    if (
++      (nameval =
++       (char *) dict_lookup (vstring_str (opt_dict_name),
++                             "additional_conditions")) == NULL)
++      name->additional_conditions = mystrdup ("");
++    else
++      name->additional_conditions = mystrdup (nameval);
++    if (msg_verbose)
++      msg_info ("pgsqlname_parse(): set additional_conditions to '%s'",
++                name->additional_conditions);
++
++    /* pgsql server hosts */
++    if (
++      (nameval =
++       (char *) dict_lookup (vstring_str (opt_dict_name), "hosts")) == NULL)
++      hosts = mystrdup ("");
++    else
++      hosts = mystrdup (nameval);
++    /* coo argv interface */
++    hosts_argv = argv_split (hosts, " ,\t\r\n");
++
++    if (hosts_argv->argc == 0)
++      {                                               /* no hosts specified,
++                                               * default to 'localhost' */
++        if (msg_verbose)
++            msg_info
++                ("pgsqlname_parse(): no hostnames specified, defaulting to 'localhost'");
++        argv_add (hosts_argv, "localhost", ARGV_END);
++        argv_terminate (hosts_argv);
++      }
++    name->len_hosts = hosts_argv->argc;
++    name->hostnames =
++
++      (char **) mymalloc ((sizeof (char *)) * name->len_hosts);
++    i = 0;
++    for (i = 0; hosts_argv->argv[i] != NULL; i++)
++      {
++        name->hostnames[i] = mystrdup (hosts_argv->argv[i]);
++        if (msg_verbose)
++            msg_info
++                ("pgsqlname_parse(): adding host '%s' to list of pgsql server hosts",
++                 name->hostnames[i]);
++      }
++    myfree (hosts);
++    vstring_free (opt_dict_name);
++    argv_free (hosts_argv);
++    return name;
++}
++
++
++/*
++ * plpgsql_init - initalize a PGSQL database.
++ *                Return NULL on failure, or a PLPGSQL * on success.
++ */
++static PLPGSQL *plpgsql_init (char *hostnames[], int len_hosts)
++{
++    PLPGSQL *PLDB;
++    int     i;
++    HOST    host;
++
++    if ((PLDB = (PLPGSQL *) mymalloc (sizeof (PLPGSQL))) == NULL)
++      {
++        msg_fatal ("mymalloc of pldb failed");
++      }
++    PLDB->len_hosts = len_hosts;
++    if ((PLDB->db_hosts = (HOST *) mymalloc (sizeof (HOST) * len_hosts))
++      == NULL)
++      return NULL;
++
++    for (i = 0; i < len_hosts; i++)
++      {
++        PLDB->db_hosts[i] = host_init (hostnames[i]);
++      }
++    return PLDB;
++}
++
++
++/* host_init - initialize HOST structure */
++static HOST host_init (char *hostname)
++{
++    HOST    host;
++
++    host.stat = STATUNTRIED;
++    host.hostname = mystrdup (hostname);
++    host.db = 0;
++    host.ts = 0;
++    return host;
++}
++
++/**********************************************************************
++ * public interface dict_pgsql_close
++ * unregister, disassociate from database, freeing appropriate memory
++ **********************************************************************/
++static void dict_pgsql_close (DICT *dict)
++{
++    int     i;
++    DICT_PGSQL *dict_pgsql = (DICT_PGSQL *) dict;
++
++    plpgsql_dealloc (dict_pgsql->pldb);
++    myfree (dict_pgsql->name->username);
++    myfree (dict_pgsql->name->password);
++    myfree (dict_pgsql->name->dbname);
++    myfree (dict_pgsql->name->table);
++    myfree (dict_pgsql->name->select_field);
++    myfree (dict_pgsql->name->where_field);
++    myfree (dict_pgsql->name->additional_conditions);
++    for (i = 0; i < dict_pgsql->name->len_hosts; i++)
++      {
++        myfree (dict_pgsql->name->hostnames[i]);
++      }
++    myfree ((char *) dict_pgsql->name->hostnames);
++    myfree ((char *) dict_pgsql->name);
++    dict_free (dict);
++}
++
++/* plpgsql_dealloc - free memory associated with PLPGSQL close databases */
++static void plpgsql_dealloc (PLPGSQL * PLDB)
++{
++    int     i;
++
++    for (i = 0; i < PLDB->len_hosts; i++)
++      {
++        if (PLDB->db_hosts[i].db)
++            PQfinish (PLDB->db_hosts[i].db);
++        myfree (PLDB->db_hosts[i].hostname);
++      }
++    myfree ((char *) PLDB->db_hosts);
++    myfree ((char *) (PLDB));
++}
++
++/* pgsql_escape_string - replace mysql_escape_string */
++void    pgsql_escape_string (char *escaped, const char *name, int len)
++{
++    int     i,
++            j;
++
++    for (i = 0, j = 0; i <= len; i++, j++)
++      {
++        if ((name[i] == '\'') || (name[i] == '\\'))
++          {
++              escaped[j] = '\\';
++              j++;
++          }
++        escaped[j] = name[i];
++      }
++}
++
++
++
++#endif
++
+diff -rU3 --new-file postfix-1.1.3-vanilla/src/util/dict_pgsql.h postfix-1.1.3/src/util/dict_pgsql.h
+--- postfix-1.1.3-vanilla/src/util/dict_pgsql.h        Thu Jan  1 01:00:00 1970
++++ postfix-1.1.3/src/util/dict_pgsql.h        Thu Mar  7 11:48:41 2002
+@@ -0,0 +1,41 @@
++#ifndef _DICT_PGSQL_H_INCLUDED_
++#define _DICT_PGSQL_H_INCLUDED_
++
++/*++
++/* NAME
++/*    dict_pgsql 3h
++/* SUMMARY
++/*    dictionary manager interface to pgsql databases
++/* SYNOPSIS
++/*    #include <dict_pgsql.h>
++/* DESCRIPTION
++/* .nf
++
++ /*
++  * Utility library.
++  */
++#include <dict.h>
++
++ /*
++  * External interface.
++  */
++#define DICT_TYPE_PGSQL       "pgsql"
++
++extern DICT *dict_pgsql_open (const char *, int, int);
++
++/* LICENSE
++/* .ad
++/* .fi
++/*    The Secure Mailer license must be distributed with this software.
++/* AUTHOR(S)
++/*    Scott Cotton
++/*    IC Group, Inc.
++/*    scott@icgroup.com
++/*
++/*    Joshua Marcus
++/*    IC Group, Inc.
++/*    josh@icgroup.com
++/*--*/
++
++#endif
++
This page took 0.06958 seconds and 4 git commands to generate.