Репозиторий ALT Linux backports/2.4
Последнее обновление: 9 июля 2008 | Пакетов: 497 | Посещений: 1491857
 поиск   регистрация   авторизация 
 
Группа :: Система/Серверы
Пакет: 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,
 };
 
design & coding: Vladimir Lettiev aka crux © 2004-2005