Группа :: Система/Серверы
Пакет: postfix
Главная Изменения Спек Патчи Загрузить Bugs and FR
Патч: postfix-2.2.9-alt-memcached.patch
diff -upk.orig postfix-2.2.9.orig/html/Makefile.in postfix-2.2.9/html/Makefile.in
--- postfix-2.2.9.orig/html/Makefile.in 2005-02-22 12:38:30 +0000
+++ postfix-2.2.9/html/Makefile.in 2005-04-01 15:23:31 +0000
@@ -17,7 +17,7 @@ COMMANDS= mailq.1.html newaliases.1.html
CONFIG = access.5.html aliases.5.html canonical.5.html relocated.5.html \
transport.5.html virtual.5.html pcre_table.5.html regexp_table.5.html \
cidr_table.5.html header_checks.5.html \
- ldap_table.5.html mysql_table.5.html pgsql_table.5.html \
+ ldap_table.5.html memcache_table.5.html mysql_table.5.html pgsql_table.5.html \
master.5.html nisplus_table.5.html generic.5.html
OTHER = postfix-manuals.html
AWK = awk '{ print; if (NR == 2) print ".pl 9999\n.ll 65" }'
@@ -253,6 +253,10 @@ master.5.html: ../proto/master
PATH=../mantools:$$PATH; \
srctoman - $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@
+memcache_table.5.html: ../proto/memcache_table
+ PATH=../mantools:$$PATH; \
+ srctoman - $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@
+
mysql_table.5.html: ../proto/mysql_table
PATH=../mantools:$$PATH; \
srctoman - $? | $(AWK) | nroff -man | uniq | $(MAN2HTML) | postlink >$@
diff -upk.orig postfix-2.2.9.orig/man/Makefile.in postfix-2.2.9/man/Makefile.in
--- postfix-2.2.9.orig/man/Makefile.in 2005-02-22 12:38:30 +0000
+++ postfix-2.2.9/man/Makefile.in 2005-04-01 15:23:31 +0000
@@ -15,7 +15,7 @@ COMMANDS= man1/postalias.1 man1/postcat.
CONFIG = man5/access.5 man5/aliases.5 man5/canonical.5 man5/relocated.5 \
man5/transport.5 man5/virtual.5 man5/pcre_table.5 man5/regexp_table.5 \
man5/cidr_table.5 man5/header_checks.5 \
- man5/body_checks.5 man5/ldap_table.5 man5/mysql_table.5 \
+ man5/body_checks.5 man5/ldap_table.5 man5/memcache_table.5 man5/mysql_table.5 \
man5/pgsql_table.5 man5/master.5 man5/nisplus_table.5 \
man5/generic.5
TOOLS = man1/smtp-sink.1 man1/smtp-source.1 man1/qmqp-sink.1 \
@@ -256,6 +256,9 @@ man5/ldap_table.5: ../proto/ldap_table
man5/master.5: ../proto/master
../mantools/srctoman - $? >$@
+man5/memcache_table.5: ../proto/memcache_table
+ ../mantools/srctoman - $? >$@
+
man5/mysql_table.5: ../proto/mysql_table
../mantools/srctoman - $? >$@
diff -upk.orig postfix-2.2.9.orig/proto/DATABASE_README.html postfix-2.2.9/proto/DATABASE_README.html
--- postfix-2.2.9.orig/proto/DATABASE_README.html 2005-02-05 23:16:06 +0000
+++ postfix-2.2.9/proto/DATABASE_README.html 2005-04-01 15:23:31 +0000
@@ -302,6 +302,11 @@ name as used in "hash:table" is the data
<dd> Perform lookups using the LDAP protocol. Configuration details
are given in the ldap_table(5). </dd>
+<dt> <b>memcache</b> (read-only) </dt>
+
+<dd> Perform memcached cache lookups. Configuration details are given
+in memcache_table(5). </dd>
+
<dt> <b>mysql</b> (read-only) </dt>
<dd> Perform MySQL database lookups. Configuration details are given
diff -upk.orig postfix-2.2.9.orig/proto/MEMCACHE_README.html postfix-2.2.9/proto/MEMCACHE_README.html
--- postfix-2.2.9.orig/proto/MEMCACHE_README.html 1970-01-01 00:00:00 +0000
+++ postfix-2.2.9/proto/MEMCACHE_README.html 2005-04-01 15:23:31 +0000
@@ -0,0 +1,109 @@
+<!doctype html public "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+
+<html>
+
+<head>
+
+<title>Postfix memcached Howto</title>
+
+<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
+
+</head>
+
+<body>
+
+<h1><img src="postfix-logo.jpg" width="203" height="98" ALT="">Postfix memcached Howto</h1>
+
+<hr>
+
+<h2>Introduction</h2>
+
+<p>The Postfix memcache map type allows you to hook up Postfix to a memcached
+server. This implementation allows for multiple memcached servers: you can use
+one for a virtual(5) table, two for an access(5) table, and three for an aliases
+(5) table if you want.</p>
+
+<p>The memcache map type can be used to reduce the load on another map type,
+e.g. pgsql. By placing the memcache map before the pgsql map, a key not
+found in the memcache will fall through to the database. You'll need to
+figure out a way to reverse populate the cache from the database yourself.</p>
+
+<p>This map type can be seen as an alternative to the proxymap(8) service.</p>
+
+<h2>Building Postfix with memcached support</h2>
+
+<p>In order to build Postfix with memcached map support, you specify
+-DHAS_MEMCACHE, and the directory where libmemcache resides (both
+memcache.c and memcache.h are used.)</p>
+
+<p> For example: </p>
+
+<blockquote>
+<pre>
+% make tidy
+% make -f Makefile.init makefiles \
+ 'CCARGS=-DHAS_MEMCACHE -I/opt/libmemcache'
+</blockquote>
+
+<p> Then just run 'make'. </p>
+
+<h2>Configuring memcached lookup tables</h2>
+
+<p> Once Postfix is built with memcache support, you can specify a
+map type in main.cf like this: </p>
+
+<blockquote>
+<pre>
+/etc/postfix/main.cf:
+ alias_maps = memcache:/etc/postfix/memcache-aliases.cf
+</pre>
+</blockquote>
+
+<p>The file /etc/postfix/memcache-aliases.cf specifies lots of information
+telling postfix how to reference the memcache instance(s). For a complete
+description, see the memcache_table(5) manual page.</p>
+
+<h2>Example: local aliases </h2>
+
+<pre>
+#
+# memcache config file for local(8) aliases(5) lookups
+#
+
+#
+# The memcached servers that Postfix will try to connect to
+# If no servers are specified, localhost is used.
+# If no port is specified, 11211 is used.
+
+servers = mc01.some.domain mc02.some.domain
+
+# The key_format to use. The default is just to use whatever postfix
+# sends us. See memcache_table(5) for more details
+key_format = %u:mail_alias
+</pre>
+
+<h2>Credits</h2>
+
+<ul>
+
+<li> This code is based upon the Postfix mysql map by Scott Cotton
+and Joshua Marcus, IC Group, Inc.
+
+<li> The PostgreSQL changes were done by Aaron Sethman.
+
+<li> The memcached changes were done by Omar Kilani.
+
+<li> Updates for Postfix 1.1.x and PostgreSQL 7.1+ and support for
+calling stored procedures were added by Philip Warner.
+
+<li> LaMont Jones was the initial Postfix pgsql maintainer.
+
+<li> Liviu Daia revised the configuration interface and added the
+main.cf configuration feature.
+
+</ul>
+
+</body>
+
+</html>
diff -upk.orig postfix-2.2.9.orig/proto/Makefile.in postfix-2.2.9/proto/Makefile.in
--- postfix-2.2.9.orig/proto/Makefile.in 2005-02-27 21:40:20 +0000
+++ postfix-2.2.9/proto/Makefile.in 2005-04-01 15:23:31 +0000
@@ -23,6 +23,7 @@ HTML = ../html/ADDRESS_CLASS_README.html
../html/LDAP_README.html \
../html/LINUX_README.html ../html/LMTP_README.html \
../html/LOCAL_RECIPIENT_README.html ../html/MAILDROP_README.html \
+ ../html/MEMCACHE_README.html \
../html/MYSQL_README.html ../html/NFS_README.html \
../html/OVERVIEW.html \
../html/PACKAGE_README.html ../html/PCRE_README.html \
@@ -57,6 +58,7 @@ README = ../README_FILES/ADDRESS_CLASS_R
../README_FILES/LDAP_README \
../README_FILES/LINUX_README ../README_FILES/LMTP_README \
../README_FILES/LOCAL_RECIPIENT_README ../README_FILES/MAILDROP_README \
+ ../README_FILES/MEMCACHE_README \
../README_FILES/MYSQL_README ../README_FILES/NFS_README \
../README_FILES/OVERVIEW \
../README_FILES/PACKAGE_README ../README_FILES/PCRE_README \
@@ -188,6 +190,9 @@ clobber:
../html/MAILDROP_README.html: MAILDROP_README.html
$(POSTLINK) $? >$@
+../html/MEMCACHE_README.html: MEMCACHE_README.html
+ $(POSTLINK) $? >$@
+
../html/MYSQL_README.html: MYSQL_README.html
$(POSTLINK) $? >$@
@@ -323,6 +328,9 @@ clobber:
../README_FILES/MAILDROP_README: MAILDROP_README.html
$(HT2READ) $? >$@
+../README_FILES/MEMCACHE_README: MEMCACHE_README.html
+ $(HT2READ) $? >$@
+
../README_FILES/MYSQL_README: MYSQL_README.html
$(HT2READ) $? >$@
diff -upk.orig postfix-2.2.9.orig/proto/memcache_table postfix-2.2.9/proto/memcache_table
--- postfix-2.2.9.orig/proto/memcache_table 1970-01-01 00:00:00 +0000
+++ postfix-2.2.9/proto/memcache_table 2005-04-01 15:23:31 +0000
@@ -0,0 +1,113 @@
+#++
+# NAME
+# memcache_table 5
+# SUMMARY
+# Postfix memcache client configuration
+# SYNOPSIS
+# \fBpostmap -q "\fIstring\fB" memcache:/etc/postfix/filename\fR
+#
+# \fBpostmap -q - memcache:/etc/postfix/\fIfilename\fR <\fIinputfile\fR
+# DESCRIPTION
+# The Postfix mail system uses optional tables for address
+# rewriting or mail routing. These tables are usually in
+# \fBdbm\fR or \fBdb\fR format.
+#
+# Alternatively, lookup tables can be specified as memcached
+# instances. In order to use memcache lookups, define a
+# memcache source as a lookup table in main.cf, for example:
+# .ti +4
+# alias_maps = memcache:/etc/postfix/memcache-aliases.cf
+#
+# The file /etc/postfix/memcache-aliases.cf has the same format as
+# the Postfix main.cf file, and can specify the parameters
+# described below.
+# ALTERNATIVE CONFIGURATION
+# .ad
+# .fi
+# For compatibility with other Postfix lookup tables, memcache
+# parameters can also be defined in main.cf. In order to do
+# that, specify as memcache source a name that doesn't begin
+# with a slash or a dot. The memcache parameters will then
+# be accessible as the name you've given the source in its
+# definition, an underscore, and the name of the parameter. For
+# example, if the map is specified as "memcache:\fImemcache\fR",
+# the parameter "servers" below would be defined in main.cf as
+# "\fImemcache\fR_servers".
+#
+# MEMCACHE PARAMETERS
+# .ad
+# .fi
+# .IP "\fBservers\fR"
+# The memcache servers that Postfix will try to connect to and query
+# from.
+# .PP
+# .ti +7
+# servers = mc01.some.domain mc02.some.domain
+# .PP
+# The following parameters provide ways to override the default
+# key used:
+# .IP "\fBkey_format\fR"
+# Format of key to use. Before the key is actually used,
+# all occurrences of %s are replaced with the address to
+# look up, %u are replaced with the user portion, and %d
+# with the domain portion. For example, to use user:mail_alias as
+# the key (where user is the user portion of the address):
+# .PP
+# .ti +7
+# key_format = %u:mail_alias
+# .PP
+# .ti +7
+# This parameter supports the following '%' expansions:
+# .RS
+# .IP "\fB\fB%s\fR\fR"
+# This is replaced by the input key. Quoting is used to make sure
+# that the input key does not add unexpected metacharacters.
+# .IP "\fB\fB%u\fR\fR"
+# When the input key is an address of the form user@domain,
+# \fB%u\fR is replaced by the quoted local part of the address.
+# If no domain is specified, \fB%u\fR is replaced by the entire
+# search string.
+# .IP "\fB\fB%d\fR\fR"
+# When the input key is an address of the form user@domain,
+# \fB%d\fR is replaced by the quoted domain part of the address.
+# When the input key has no domain qualifier, \fB%d\fR is replaced
+# by the entire search string.
+# .RE
+# SEE ALSO
+# postmap(1), Postfix lookup table manager
+# postconf(5), configuration parameters
+# ldap_table(5), LDAP lookup tables
+# mysql_table(5), MySQL lookup tables
+# pgsql_table(5), PostgreSQL lookup tables
+# README FILES
+# .ad
+# .fi
+# Use "\fBpostconf readme_directory\fR" or
+# "\fBpostconf html_directory\fR" to locate this information.
+# .na
+# .nf
+# DATABASE_README, Postfix lookup table overview
+# MEMCACHE_README, Postfix memcache client guide
+# LICENSE
+# .ad
+# .fi
+# The Secure Mailer license must be distributed with this software.
+# HISTORY
+# memcache support was written on the 1st of April, 2005.
+# AUTHOR(S)
+# Based on the MySQL client by:
+# Scott Cotton, Joshua Marcus
+# IC Group, Inc.
+#
+# Ported to PostgreSQL by:
+# Aaron Sethman
+#
+# Modified for memcached by:
+# Omar Kilani
+#
+# Further enhanced by:
+# Liviu Daia
+# Institute of Mathematics of the Romanian Academy
+# P.O. BOX 1-764
+# RO-014700 Bucharest, ROMANIA
+#--
diff -upk.orig postfix-2.2.9.orig/src/global/Makefile.in postfix-2.2.9/src/global/Makefile.in
--- postfix-2.2.9.orig/src/global/Makefile.in 2006-03-18 23:55:56 +0000
+++ postfix-2.2.9/src/global/Makefile.in 2006-03-19 00:08:03 +0000
@@ -3,7 +3,7 @@ SRCS = abounce.c anvil_clnt.c been_here.
canon_addr.c cfg_parser.c cleanup_strerror.c cleanup_strflags.c \
clnt_stream.c debug_peer.c debug_process.c defer.c db_common.c \
deliver_completed.c deliver_flock.c deliver_pass.c deliver_request.c \
- dict_ldap.c dict_mysql.c dict_pgsql.c dict_proxy.c domain_list.c \
+ dict_ldap.c dict_mysql.c dict_pgsql.c dict_memcache.c dict_proxy.c domain_list.c \
dot_lockfile.c dot_lockfile_as.c ext_prop.c file_id.c flush_clnt.c \
header_opts.c header_token.c hold_message.c input_transp.c \
is_header.c log_adhoc.c mail_addr.c mail_addr_crunch.c \
@@ -57,7 +57,7 @@ HDRS = abounce.h anvil_clnt.h been_here.
canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \
debug_peer.h debug_process.h defer.h deliver_completed.h \
deliver_flock.h deliver_pass.h deliver_request.h dict_ldap.h \
- dict_mysql.h dict_pgsql.h dict_proxy.h domain_list.h dot_lockfile.h \
+ dict_mysql.h dict_pgsql.h dict_memcache.h dict_proxy.h domain_list.h dot_lockfile.h \
dot_lockfile_as.h ext_prop.h file_id.h flush_clnt.h header_opts.h \
header_token.h hold_message.h input_transp.h is_header.h \
lex_822.h log_adhoc.h mail_addr.h mail_addr_crunch.h \
@@ -83,7 +83,8 @@ DEF_MAIL_VERSION = unknown
DICT_LDAP = dict_ldap-$(DEF_MAIL_VERSION).so
DICT_MYSQL = dict_mysql-$(DEF_MAIL_VERSION).so
DICT_PGSQL = dict_pgsql-$(DEF_MAIL_VERSION).so
-DICTS = $(DICT_LDAP) $(DICT_MYSQL) $(DICT_PGSQL)
+DICT_MEMCACHE = dict_memcache-$(DEF_MAIL_VERSION).so
+DICTS = $(DICT_LDAP) $(DICT_MYSQL) $(DICT_PGSQL) $(DICT_MEMCACHE)
LIB = libglobal.a
TESTPROG= domain_list dot_lockfile mail_addr_crunch mail_addr_find \
mail_addr_map mail_date maps mynetworks mypwd namadr_list \
@@ -120,6 +121,9 @@ $(DICT_MYSQL): dict_mysql.o
$(DICT_PGSQL): dict_pgsql.o
gcc -shared -Wl,-soname,$@ -o $@ $? -lpq $(LIBS) $(SYSLIBS)
+$(DICT_MEMCACHE): dict_memcache.o
+ gcc -shared -Wl,-soname,$@ -o $@ $? -lmemcache $(LIBS) $(SYSLIBS)
+
$(LIB): $(OBJS)
$(AR) $(ARFL) $(LIB) $?
$(RANLIB) $(LIB)
@@ -655,6 +659,25 @@ dict_ldap.o: string_list.h
dict_ldap.o: ../../include/match_list.h
dict_ldap.o: ../../include/match_ops.h
dict_ldap.o: dict_ldap.h
+dict_memcache.o: dict_memcache.c
+dict_memcache.o: ../../include/sys_defs.h
+dict_memcache.o: ../../include/dict.h
+dict_memcache.o: ../../include/vstream.h
+dict_memcache.o: ../../include/vbuf.h
+dict_memcache.o: ../../include/argv.h
+dict_memcache.o: ../../include/msg.h
+dict_memcache.o: ../../include/mymalloc.h
+dict_memcache.o: ../../include/vstring.h
+dict_memcache.o: ../../include/split_at.h
+dict_memcache.o: ../../include/find_inet.h
+dict_memcache.o: ../../include/myrand.h
+dict_memcache.o: ../../include/events.h
+dict_memcache.o: cfg_parser.h
+dict_memcache.o: db_common.h
+dict_memcache.o: string_list.h
+dict_memcache.o: ../../include/match_list.h
+dict_memcache.o: ../../include/match_ops.h
+dict_memcache.o: dict_memcache.h
dict_mysql.o: dict_mysql.c
dict_mysql.o: ../../include/sys_defs.h
dict_mysql.o: ../../include/dict.h
diff -upk.orig postfix-2.2.9.orig/src/global/dict_memcache.c postfix-2.2.9/src/global/dict_memcache.c
--- postfix-2.2.9.orig/src/global/dict_memcache.c 1970-01-01 00:00:00 +0000
+++ postfix-2.2.9/src/global/dict_memcache.c 2005-04-01 15:23:31 +0000
@@ -0,0 +1,518 @@
+
+/*++
+/* NAME
+/* dict_memcache 3
+/* SUMMARY
+/* dictionary manager interface to memcached
+/* SYNOPSIS
+/* #include <dict_memcache.h>
+/*
+/* DICT *dict_memcache_open(name, open_flags, dict_flags)
+/* const char *name;
+/* int open_flags;
+/* int dict_flags;
+/* DESCRIPTION
+/* dict_memcache_open() creates a dictionary of type 'memcache'. This
+/* dictionary is an interface for the postfix key->value mappings
+/* to memcached. The result is a pointer to the installed dictionary,
+/* or a null pointer in case of problems.
+/*
+/* The memcache dictionary can manage multiple connections to
+/* different memcached servers. The intent of this feature is to
+/* eliminate a single point of failure for mail systems that would
+/* otherwise rely on a single memcached server.
+/* .PP
+/* Arguments:
+/* .IP name
+/* Either the path to the memcached configuration file (if it
+/* starts with '/' or '.'), or the prefix which will be used to
+/* obtain main.cf configuration parameters for this search.
+/*
+/* In the first case, the configuration parameters below are
+/* specified in the file as \fIname\fR=\fBvalue\fR pairs.
+/*
+/* In the second case, the configuration parameters are
+/* prefixed with the value of \fIname\fR and an underscore,
+/* and they are specified in main.cf. For example, if this
+/* value is \fIservers\fR, the parameters would look like
+/* \fImemcache_servers\fR, \fImemcache_key_format\fR, and so on.
+/* .IP other_name
+/* reference for outside use.
+/* .IP open_flags
+/* Must be O_RDONLY.
+/* .IP dict_flags
+/* See dict_open(3).
+/*
+/* .PP
+/* Configuration parameters:
+/*
+/* The parameters encode a number of pieces of information:
+/* .IP \fIservers\fR
+/* memcached servers to connect to.
+/* .IP \fIkey_format\fR
+/* Format of key to use. Before the key is actually used,
+/* all occurrences of %s are replaced with the address to
+/* look up, %u are replaced with the user portion, and %d
+/* with the domain portion.
+/*
+/* .PP
+/* For example, if you wish to use two memcached servers, with
+/* a key that looks like \fIuser:mail_alias\fR:
+/* .PP
+/* \fIservers\fR = \fBmc01.some.domain\fR \fBmc02.some.domain\fR
+/* .br
+/* \fIkey_format\fR = \fB%u:mail_alias\fR
+/* .PP
+/* SEE ALSO
+/* dict(3) generic dictionary manager
+/* AUTHOR(S)
+/* Omar Kilani
+/* omar@tinysofa.com
+/*
+/* Based upon dict_pgsql.c by
+/*
+/* Aaron Sethman
+/* androsyn@ratbox.org
+/*
+/* Based upon dict_mysql.c 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_MEMCACHE
+#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 <memcache.h>
+
+
+/* Utility library. */
+
+#include "dict.h"
+#include "msg.h"
+#include "mymalloc.h"
+#include "argv.h"
+#include "vstring.h"
+#include "split_at.h"
+#include "find_inet.h"
+#include "myrand.h"
+#include "events.h"
+
+/* Global library. */
+
+#include "cfg_parser.h"
+
+/* Application-specific. */
+
+#include "dict_memcache.h"
+
+typedef struct
+{
+ char *hostname;
+ char *name;
+ char *port;
+} SERVERS;
+
+typedef struct
+{
+ struct memcache_ctxt *mc_ctxt; /* memcache context */
+ struct memcache *mc; /* memcache instance */
+ int len_mc; /* number of hosts */
+ SERVERS **mc_servers; /* hosts on which memcached resides */
+} PLMEMCACHE;
+
+typedef struct
+{
+ CFG_PARSER *parser;
+ char **servers;
+ int len_servers;
+ char *key_format;
+} MEMCACHE_NAME;
+
+typedef struct
+{
+ DICT dict;
+ PLMEMCACHE *plmc;
+ MEMCACHE_NAME *name;
+} DICT_MEMCACHE;
+
+
+/* Just makes things a little easier for me.. */
+#define MEMCACHE_REQ struct memcache_req
+#define MEMCACHE_RES struct memcache_res
+
+/* internal function declarations */
+static PLMEMCACHE *plmemcache_init (char *servers[], int);
+static VSTRING *plmemcache_get (PLMEMCACHE *, const char *);
+static void plmemcache_dealloc (PLMEMCACHE *);
+static const char *dict_memcache_lookup (DICT *, const char *);
+DICT *dict_memcache_open (const char *, int, int);
+static void dict_memcache_close (DICT *);
+static MEMCACHE_NAME *memcachename_parse (const char *);
+static SERVERS *server_init (const char *);
+
+
+
+/**********************************************************************
+ * public interface dict_memcache_lookup
+ * find memcache entry return 0 if no alias found, set dict_errno
+ * on errors to DICT_ERROR_RETRY and set dict_errno to 0 on success
+ *********************************************************************/
+
+/*
+ * expand a filter (lookup or result)
+ */
+static void dict_memcache_expand_filter (char *filter, char *value,
+ VSTRING *out)
+{
+ const char *myname = "dict_memcache_expand_filter";
+ char *sub,
+ *end;
+
+ /*
+ * Yes, replace all instances of %s with the address to look up. Replace
+ * %u with the user portion, and %d with the domain portion.
+ */
+ sub = filter;
+ end = sub + strlen (filter);
+ while (sub < end)
+ {
+
+ /*
+ * Make sure it's %[sud] and not something else. For backward
+ * compatibilty, treat anything other than %u or %d as %s, with a
+ * warning.
+ */
+ if (*(sub) == '%')
+ {
+ char *u = value;
+ char *p = strrchr (u, '@');
+
+ switch (*(sub + 1))
+ {
+ case 'd':
+ if (p)
+ vstring_strcat (out, p + 1);
+ break;
+ case 'u':
+ if (p)
+ vstring_strncat (out, u, p - u);
+ else
+ vstring_strcat (out, u);
+ break;
+ default:
+ msg_warn
+ ("%s: Invalid filter substitution format '%%%c'!",
+ myname, *(sub + 1));
+ break;
+ case 's':
+ vstring_strcat (out, u);
+ break;
+ }
+ sub++;
+ }
+ else
+ vstring_strncat (out, sub, 1);
+ sub++;
+ }
+}
+
+static const char *dict_memcache_lookup (DICT *dict, const char *name)
+{
+ DICT_MEMCACHE *dict_memcache;
+ PLMEMCACHE *plmc;
+ static VSTRING *result;
+ static VSTRING *key = 0;
+
+ dict_memcache = (DICT_MEMCACHE *) dict;
+ plmc = dict_memcache->plmc;
+ /* initialization for key */
+ key = vstring_alloc (24);
+
+ if (dict_memcache->name->key_format)
+ {
+ msg_info ("dict_memcache_lookup: using key_format '%s'",
+ dict_memcache->name->key_format);
+ dict_memcache_expand_filter (dict_memcache->name->key_format, name,
+ key);
+ }
+ else
+ {
+ vstring_strcpy (key, name);
+ }
+
+ /* do the query - set dict_errno & cleanup if there's an error */
+ if ((result = plmemcache_get (plmc, vstring_str (key))) == 0)
+ {
+ /* Since we're just a cache, we don't care if bad things happened
+ -or- if there's no result. libmemcache will just try again for
+ us later. */
+ msg_info ("dict_memcache_lookup: %s returned nothing, returning 0",
+ vstring_str (key));
+ dict_errno = 0;
+ vstring_free (key);
+ return 0;
+ }
+ dict_errno = 0;
+ msg_info ("dict_memcache_lookup: %s returned %s", vstring_str (key),
+ vstring_str (result));
+ /* free the vstring query */
+ vstring_free (key);
+
+ return vstring_str (result);
+}
+
+/*
+ * plmemcache_get - process a memcache get. Return VSTRING* on success.
+ * On failure, or key not found, return 0;
+ */
+
+static VSTRING *plmemcache_get (PLMEMCACHE * PLMC, const char *key)
+{
+ MEMCACHE_REQ *req = 0;
+ MEMCACHE_RES *res = 0;
+ VSTRING *value = 0;
+
+ req = mcm_req_new (PLMC->mc_ctxt);
+ res = mcm_req_add_ref (PLMC->mc_ctxt, req, key, strlen (key));
+
+ if (res == NULL)
+ {
+ msg_warn ("Could not allocate new mc_res");
+ mcm_req_free (PLMC->mc_ctxt, req);
+ return 0;
+ }
+
+ msg_info ("plmemcache_get: fetching key %s from memcache", key);
+
+ mcm_get (PLMC->mc_ctxt, PLMC->mc, req);
+
+ if (mcm_res_found (PLMC->mc_ctxt, res) && res->bytes)
+ {
+ /* Found key - Caller must free this vstring */
+ value = vstring_alloc (res->bytes);
+ vstring_strncpy (value, res->val, res->bytes);
+ mcm_res_free (PLMC->mc_ctxt, req, res);
+ mcm_req_free (PLMC->mc_ctxt, req);
+ msg_info ("plmemcache_get: key %s => %s", key, vstring_str (value));
+ return value;
+ }
+ else
+ {
+ msg_info ("plmemcache_get: nothing found for key %s", key);
+ mcm_req_free (PLMC->mc_ctxt, req);
+ return 0;
+ }
+
+ msg_info ("plmemcache_get: nothing found for key %s", key);
+ mcm_req_free (PLMC->mc_ctxt, req);
+ return 0;
+}
+
+/**********************************************************************
+ * public interface dict_memcache_open
+ * create association with database with appropriate values
+ * parse the map's config file
+ * allocate memory
+ **********************************************************************/
+DICT *dict_memcache_open (const char *name, int open_flags, int dict_flags)
+{
+ DICT_MEMCACHE *dict_memcache;
+
+ /*
+ * Sanity checks.
+ */
+ if (open_flags != O_RDONLY)
+ msg_fatal ("%s:%s map requires O_RDONLY access mode",
+ DICT_TYPE_MEMCACHE, name);
+
+ dict_memcache = (DICT_MEMCACHE *) dict_alloc (DICT_TYPE_MEMCACHE, name,
+ sizeof (DICT_MEMCACHE));
+ dict_memcache->dict.lookup = dict_memcache_lookup;
+ dict_memcache->dict.close = dict_memcache_close;
+ dict_memcache->name = memcachename_parse (name);
+ dict_memcache->plmc = plmemcache_init (dict_memcache->name->servers,
+ dict_memcache->name->len_servers);
+ dict_memcache->dict.flags = dict_flags | DICT_FLAG_FIXED;
+ if (dict_memcache->plmc == NULL)
+ msg_fatal ("couldn't intialize plmc!\n");
+ return &dict_memcache->dict;
+}
+
+/* memcachename_parse - parse memcache configuration file */
+static MEMCACHE_NAME *memcachename_parse (const char *memcachecf)
+{
+ const char *myname = "memcachename_parse";
+ int i;
+ char *servers;
+ MEMCACHE_NAME *name = (MEMCACHE_NAME *) mymalloc (sizeof (MEMCACHE_NAME));
+ ARGV *servers_argv;
+
+ name->parser = cfg_parser_alloc (memcachecf);
+
+ name->key_format = cfg_get_str (name->parser, "key_format", NULL, 0, 0);
+
+ /* server hosts */
+ servers = cfg_get_str (name->parser, "servers", "", 0, 0);
+
+ /* coo argv interface */
+ servers_argv = argv_split (servers, " ,\t\r\n");
+ if (servers_argv->argc == 0)
+ { /* no hosts specified,
+ * default to 'localhost' */
+ if (msg_verbose)
+ msg_info
+ ("%s: %s: no hostnames specified, defaulting to 'localhost'",
+ myname, memcachecf);
+ argv_add (servers_argv, "localhost:11211", ARGV_END);
+ argv_terminate (servers_argv);
+ }
+ name->len_servers = servers_argv->argc;
+ name->servers =
+ (char **) mymalloc ((sizeof (char *)) * name->len_servers);
+ i = 0;
+ for (i = 0; servers_argv->argv[i] != NULL; i++)
+ {
+ name->servers[i] = mystrdup (servers_argv->argv[i]);
+ if (msg_verbose)
+ msg_info
+ ("%s: %s: adding host '%s' to list of memcache server hosts",
+ myname, memcachecf, name->servers[i]);
+ }
+ myfree (servers);
+ argv_free (servers_argv);
+ return name;
+}
+
+
+/*
+ * plmemcache_init - initalize a memcache instance.
+ * Return NULL on failure, or a PLMEMCACHE * on success.
+ */
+static PLMEMCACHE *plmemcache_init (char *servers[], int len_mc)
+{
+ PLMEMCACHE *PLMC;
+ int i;
+
+ struct memcache_ctxt *mc_ctxt;
+ struct memcache *mc;
+
+ if ((PLMC = (PLMEMCACHE *) mymalloc (sizeof (PLMEMCACHE))) == NULL)
+ {
+ msg_fatal ("mymalloc of plmc failed");
+ }
+
+ mc_ctxt =
+ mcMemNewCtxt ((mcFreeFunc) myfree, (mcMallocFunc) mymalloc, NULL,
+ (mcReallocFunc) myrealloc);
+ if (mc_ctxt == NULL)
+ {
+ msg_fatal ("error creating memcache context");
+ }
+
+ mcMemSetup ((mcFreeFunc) myfree, (mcMallocFunc) mymalloc, NULL,
+ (mcReallocFunc) myrealloc);
+ mc = mcm_new (mc_ctxt);
+ if (mc == NULL)
+ {
+ msg_fatal ("error creating memcache object");
+ }
+
+ PLMC->mc_ctxt = mc_ctxt;
+ PLMC->mc = mc;
+
+ PLMC->len_mc = len_mc;
+ if ((PLMC->mc_servers =
+ (SERVERS **) mymalloc (sizeof (SERVERS *) * len_mc)) == NULL)
+ return NULL;
+
+ for (i = 0; i < len_mc; i++)
+ {
+ PLMC->mc_servers[i] = server_init (servers[i]);
+ mcm_server_add2 (PLMC->mc_ctxt, PLMC->mc,
+ PLMC->mc_servers[i]->name,
+ strlen (PLMC->mc_servers[i]->name),
+ PLMC->mc_servers[i]->port,
+ strlen (PLMC->mc_servers[i]->port));
+ }
+
+ return PLMC;
+}
+
+
+/* server_init - initialize SERVERS structure */
+static SERVERS *server_init (const char *hostname)
+{
+ const char *myname = "memcache server_init";
+ SERVERS *host = (SERVERS *) mymalloc (sizeof (SERVERS));
+ const char *d = hostname;
+
+ host->hostname = mystrdup (hostname);
+
+ host->name = mystrdup (d);
+ host->port = split_at_right (host->name, ':');
+
+ if (msg_verbose > 1)
+ msg_info ("%s: host=%s, port=%s", myname, host->name,
+ host->port ? host->port : "11211");
+ return host;
+}
+
+/**********************************************************************
+ * public interface dict_memcache_close
+ * unregister, freeing appropriate memory
+ **********************************************************************/
+static void dict_memcache_close (DICT *dict)
+{
+ int i;
+ DICT_MEMCACHE *dict_memcache = (DICT_MEMCACHE *) dict;
+
+ plmemcache_dealloc (dict_memcache->plmc);
+ cfg_parser_free (dict_memcache->name->parser);
+ for (i = 0; i < dict_memcache->name->len_servers; i++)
+ {
+ myfree (dict_memcache->name->servers[i]);
+ }
+ myfree ((char *) dict_memcache->name->servers);
+ myfree ((char *) dict_memcache->name);
+ dict_free (dict);
+}
+
+/* plmemcache_dealloc - free memory associated with PLMEMCACHE free memcache instance */
+static void plmemcache_dealloc (PLMEMCACHE * PLMC)
+{
+ int i;
+
+ for (i = 0; i < PLMC->len_mc; i++)
+ {
+ myfree (PLMC->mc_servers[i]->hostname);
+ myfree ((char *) PLMC->mc_servers[i]);
+ }
+ myfree ((char *) PLMC->mc_servers);
+
+ mcm_free (PLMC->mc_ctxt, PLMC->mc);
+ mcMemFreeCtxt (PLMC->mc_ctxt);
+
+ myfree ((char *) (PLMC));
+}
+
+#endif
+
diff -upk.orig postfix-2.2.9.orig/src/global/dict_memcache.h postfix-2.2.9/src/global/dict_memcache.h
--- postfix-2.2.9.orig/src/global/dict_memcache.h 1970-01-01 00:00:00 +0000
+++ postfix-2.2.9/src/global/dict_memcache.h 2005-04-01 15:23:31 +0000
@@ -0,0 +1,39 @@
+#ifndef _DICT_MEMCACHE_INCLUDED_
+#define _DICT_MEMCACHE_INCLUDED_
+
+/*++
+/* NAME
+/* dict_memcache 3h
+/* SUMMARY
+/* dictionary manager interface to memcached
+/* SYNOPSIS
+/* #include <dict_memcache.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * Utility library.
+ */
+#include <dict.h>
+
+ /*
+ * External interface.
+ */
+#define DICT_TYPE_MEMCACHE "memcache"
+
+extern DICT *dict_memcache_open (const char *name, int unused_flags,
+ int dict_flags);
+
+/* AUTHOR(S)
+/* Omar Kilani
+/* omar@tinysofa.com
+/*
+/* Based upon dict_pgsql.c by
+/*
+/* Aaron Sethman
+/* androsyn@ratbox.org
+/*
+/*--*/
+
+#endif
+
diff -upk.orig postfix-2.2.9.orig/src/global/mail_dict.c postfix-2.2.9/src/global/mail_dict.c
--- postfix-2.2.9.orig/src/global/mail_dict.c 2006-03-18 23:55:56 +0000
+++ postfix-2.2.9/src/global/mail_dict.c 2006-03-19 00:08:03 +0000
@@ -36,6 +36,7 @@
#include <dict_ldap.h>
#include <dict_mysql.h>
#include <dict_pgsql.h>
+#include <dict_memcache.h>
#include <mail_dict.h>
typedef struct {
@@ -55,6 +56,9 @@ static DICT_OPEN_INFO dict_open_info[] =
#ifdef HAS_PGSQL
DICT_TYPE_PGSQL, dict_pgsql_open,
#endif
+#ifdef HAS_MEMCACHE
+ DICT_TYPE_MEMCACHE, dict_memcache_open,
+#endif
#endif /* NO_DYNAMIC_MAPS */
0,
};