diff -urN README_FILES/SRS_README.orig README_FILES/SRS_README
--- README_FILES/SRS_README.orig	1970-01-01 01:00:00.000000000 +0100
+++ README_FILES/SRS_README	2012-02-21 14:22:05.000000000 +0100
@@ -0,0 +1,56 @@
+
+CREDITS:
+
+- originally written by Shevek <srs@anarres.org>
+- fixes and porting to postfix 2.1 by Branko F. Gracnar <bfg@frost.ath.cx>
+- redesigned and ported to debian postfix 2.7.0 by Chris <chris@codefrickler.de>
+
+SYNOPSIS:
+Works with all address classes (not limited to local domain).
+Doesn't depend on .forward-files or alias_maps.
+SMTPD accepts valid srs addresses without further configuration.
+Sender gets rewritten only when necessary:
+- rewrite after queuing (after separation to on- and off-site destinations)
+- rewrite only if sender and recipient are off-site and host is not a relay for recipient
+Alias domain can be chosen automatically from original on-site-recipient.
+
+
+USAGE:
+
+1) Apply the patch.
+
+2) Create makefiles with
+
+make makefiles CCARGS="-DHAS_SRS -I<directory-containing--srs2.h>" AUXLIBS="-L<directory-containing--libsrs2.so> -lsrs2"
+
+
+3) Build.
+
+4) Add the following global configuration variables to main.cf:
+All variables are optional, except where stated:
+
+	srs_domain               (string)
+		A domain to use in rewritten addresses. This must point only
+		to machines which know the encoding secret used by this
+		system. It defaults to $myorigin. If set to the emtpy
+		string, use domain from original recipient if host is final
+		destination, otherwise use $myorigin.
+	srs_hashlength           (int)
+		The hash length to generate in a rewritten address.
+	srs_hashmin              (int)
+		The hash length to require when checking an address.
+	srs_maxage               (int)
+		The maximum permitted age of a rewritten address.
+	srs_secrets              (string)
+		[required] A list of secrets with which to generate
+		and check addresses.
+	srs_separator            (string)
+		The separator to appear immediately after SRS[01] in
+		rewritten addresses.
+
+
+See http://www.libsrs2.org/ for more information about the meaning
+of these variables. They are standard across MTAs.
+
+5) Fire up and enjoy.
+
diff -urN src/cleanup/cleanup_addr.c.orig src/cleanup/cleanup_addr.c
--- src/cleanup/cleanup_addr.c.orig	2012-02-21 14:21:34.000000000 +0100
+++ src/cleanup/cleanup_addr.c	2012-02-21 14:22:05.000000000 +0100
@@ -163,6 +163,10 @@
 {
     VSTRING *clean_addr = vstring_alloc(100);
     const char *bcc;
+#ifdef HAS_SRS
+    int srs_state;
+    VSTRING *srs_rcpt;
+#endif
 
     /*
      * Note: an unqualified envelope address is for all practical purposes
@@ -174,6 +178,14 @@
     cleanup_rewrite_internal(MAIL_ATTR_RWR_LOCAL,
 			     clean_addr, *buf ? buf : var_empty_addr);
     if (state->flags & CLEANUP_FLAG_MAP_OK) {
+#ifdef HAS_SRS	
+	if ((srs_state = postfix_srs_reverse(STR(clean_addr), &srs_rcpt)) < 0) {
+            /* XXX errors */
+        } else if (srs_state == 1) {
+            vstring_free(clean_addr);
+            clean_addr = srs_rcpt;
+        }
+#endif
 	if (cleanup_rcpt_canon_maps
 	    && (cleanup_rcpt_canon_flags & CLEANUP_CANON_FLAG_ENV_RCPT))
 	    cleanup_map11_internal(state, clean_addr, cleanup_rcpt_canon_maps,
diff -urN src/global/mail_params.c.orig src/global/mail_params.c
--- src/global/mail_params.c.orig	2012-02-21 14:21:34.000000000 +0100
+++ src/global/mail_params.c	2012-02-21 14:22:05.000000000 +0100
@@ -308,6 +308,15 @@
 bool    var_long_queue_ids;
 bool    var_daemon_open_fatal;
 
+#ifdef HAS_SRS
+int     var_srs_hashlength;
+int     var_srs_hashmin;
+int     var_srs_maxage;
+char    *var_srs_secrets;
+char    *var_srs_separator;
+char    *var_srs_domain;
+#endif
+
 const char null_format_string[1] = "";
 
 /* check_myhostname - lookup hostname and validate */
@@ -579,6 +588,11 @@
 	VAR_INT_FILT_CLASSES, DEF_INT_FILT_CLASSES, &var_int_filt_classes, 0, 0,
 	/* multi_instance_wrapper may have dependencies but not dependents. */
 	VAR_MULTI_WRAPPER, DEF_MULTI_WRAPPER, &var_multi_wrapper, 0, 0,
+#ifdef HAS_SRS
+	VAR_SRS_SECRETS, DEF_SRS_SECRETS, &var_srs_secrets, 0, 0,
+	VAR_SRS_SEPARATOR, DEF_SRS_SEPARATOR, &var_srs_separator, 1, 1,
+	VAR_SRS_DOMAIN, DEF_SRS_DOMAIN, &var_srs_domain, 0, 0,
+#endif
 	0,
     };
     static const CONFIG_STR_FN_TABLE function_str_defaults_2[] = {
@@ -602,6 +616,11 @@
 	VAR_MIME_BOUND_LEN, DEF_MIME_BOUND_LEN, &var_mime_bound_len, 1, 0,
 	VAR_DELAY_MAX_RES, DEF_DELAY_MAX_RES, &var_delay_max_res, MIN_DELAY_MAX_RES, MAX_DELAY_MAX_RES,
 	VAR_INET_WINDOW, DEF_INET_WINDOW, &var_inet_windowsize, 0, 0,
+#ifdef HAS_SRS
+	VAR_SRS_HASHLENGTH, DEF_SRS_HASHLENGTH, &var_srs_hashlength, 1, 20,
+	VAR_SRS_HASHMIN, DEF_SRS_HASHMIN, &var_srs_hashmin, 1, 20,
+	VAR_SRS_MAXAGE, DEF_SRS_MAXAGE, &var_srs_maxage, 1, 0,
+#endif
 	0,
     };
     static const CONFIG_LONG_TABLE long_defaults[] = {
diff -urN src/global/mail_params.h.orig src/global/mail_params.h
--- src/global/mail_params.h.orig	2012-02-21 14:21:34.000000000 +0100
+++ src/global/mail_params.h	2012-02-21 14:22:41.000000000 +0100
@@ -1981,6 +1981,35 @@
 #define DEF_ALLOW_UNTRUST_ROUTE	0
 extern bool var_allow_untrust_route;
 
+/**
+ * SRS. Shevek <srs@anarres.org>, updated by Chris <chris@codefrickler.de>
+ */
+#ifdef HAS_SRS
+#define VAR_SRS_HASHLENGTH		"srs_hashlength"
+#define DEF_SRS_HASHLENGTH		4
+extern int var_srs_hashlength;
+
+#define VAR_SRS_HASHMIN			"srs_hashmin"
+#define DEF_SRS_HASHMIN			4
+extern int var_srs_hashmin;
+
+#define VAR_SRS_MAXAGE			"srs_maxage"
+#define DEF_SRS_MAXAGE			21
+extern int var_srs_maxage;
+
+#define VAR_SRS_SECRETS			"srs_secrets"
+#define DEF_SRS_SECRETS			""
+extern char *var_srs_secrets;
+
+#define VAR_SRS_DOMAIN			"srs_domain"
+#define DEF_SRS_DOMAIN			"$myorigin"
+extern char *var_srs_domain;
+
+#define VAR_SRS_SEPARATOR		"srs_separator"
+#define DEF_SRS_SEPARATOR		"="
+extern char *var_srs_separator;
+#endif
+
  /*
   * Names of specific restrictions, and the corresponding configuration
   * parameters that control the status codes sent in response to rejected
diff -urN src/global/Makefile.in.orig src/global/Makefile.in
--- src/global/Makefile.in.orig	2012-02-21 14:21:34.000000000 +0100
+++ src/global/Makefile.in	2012-02-21 14:22:05.000000000 +0100
@@ -29,7 +29,7 @@
 	user_acl.c valid_mailhost_addr.c verify.c verify_clnt.c \
 	verp_sender.c wildcard_inet_addr.c xtext.c delivered_hdr.c \
 	fold_addr.c header_body_checks.c mkmap_proxy.c data_redirect.c \
-	match_service.c mail_conf_nint.c addr_match_list.c mail_conf_nbool.c \
+	match_service.c mail_conf_nint.c addr_match_list.c mail_conf_nbool.c srs.c \
 	smtp_reply_footer.c safe_ultostr.c verify_sender_addr.c \
 	dict_memcache.c mail_version.c memcache_proto.c server_acl.c \
 	mkmap_fail.c
@@ -63,7 +63,7 @@
 	user_acl.o valid_mailhost_addr.o verify.o verify_clnt.o \
 	verp_sender.o wildcard_inet_addr.o xtext.o delivered_hdr.o \
 	fold_addr.o header_body_checks.o mkmap_proxy.o data_redirect.o \
-	match_service.o mail_conf_nint.o addr_match_list.o mail_conf_nbool.o \
+	match_service.o mail_conf_nint.o addr_match_list.o mail_conf_nbool.o srs.o \
 	smtp_reply_footer.o safe_ultostr.o verify_sender_addr.o \
 	dict_memcache.o mail_version.o memcache_proto.o server_acl.o \
 	mkmap_fail.o
diff -urN src/global/srs.c.orig src/global/srs.c
--- src/global/srs.c.orig	1970-01-01 01:00:00.000000000 +0100
+++ src/global/srs.c	2012-02-21 14:22:27.000000000 +0100
@@ -0,0 +1,144 @@
+/*++
+/* NAME
+/*	srs 3
+/* SUMMARY
+/*	Sender Rewriting Scheme
+/* SYNOPSIS
+/*	void	postfix_srs_reverse(rcpt, decoded)
+/*	const char *rcpt
+/*	VSTRING **decoded
+/*
+/*	int postfix_srs_forward(sender, alias, encoded)
+/*	const char *sender
+/*	const char *alias
+/*	VSTRING **decoded
+/* DESCRIPTION
+/*	This module rewrites addresses according to the Sender Rewriting
+/*  Scheme, documented at http://www.libsrs2.org/.
+/*
+/*	srs_reverse() reverse-rewrites the rewritten form of an address
+/*
+/*	srs_forward() rewrites the envelope sender using alias domain
+/*
+/* DIAGNOSTICS
+/* LICENSE
+/* .ad
+/* .fi
+/*	The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*	Shevek <srs@anarres.org>
+/*	Chris <chris@codefrickler.de>
+/*--*/
+
+#ifdef HAS_SRS
+
+/* System library. */
+
+#include <stdlib.h>
+#include <sys_defs.h>
+#include <string.h>
+
+#include <srs2.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <vstring.h>
+#include <mymalloc.h>
+#include <stringops.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+
+#define SRS_FAIL_UNLESS(x) do {	int __ret = (x); if (__ret != SRS_SUCCESS) msg_fatal("SRS configuration error: %s", srs_strerror(__ret)); } while(0)
+
+/* my function declarations */
+int postfix_srs_forward (const char *sender, const char *alias, VSTRING **encoded);
+int postfix_srs_reverse (const char *rcpt, VSTRING **decoded);
+
+static srs_t *srs;
+
+static void postfix_srs_init (void) {
+	char *saved_secrets;
+	char *secret;
+	char *ptr;
+
+	if (srs == NULL) {
+		/* XXX Can't use memory functions from postfix because of inconsistensies in libsrs2
+		srs_set_malloc((srs_malloc_t)mymalloc, (srs_realloc_t)myrealloc, (srs_free_t)myfree);
+		*/
+
+		srs = srs_new();
+		/* avoid sender-domain-check, since we have already done this ourselves */
+		SRS_FAIL_UNLESS(srs_set_alwaysrewrite(srs, 1));
+		SRS_FAIL_UNLESS(srs_set_hashlength(srs, var_srs_hashlength));
+		SRS_FAIL_UNLESS(srs_set_hashmin(srs, var_srs_hashmin));
+		SRS_FAIL_UNLESS(srs_set_maxage(srs, var_srs_maxage));
+		SRS_FAIL_UNLESS(srs_set_separator(srs, var_srs_separator[0]));
+		
+		ptr = saved_secrets = mystrdup(var_srs_secrets);
+		while ((secret = mystrtok(&ptr, ", \t\r\n")) != 0) {
+			SRS_FAIL_UNLESS(srs_add_secret(srs, secret));
+		}
+		myfree(saved_secrets);
+	}
+}
+
+int postfix_srs_reverse(const char *rcpt, VSTRING **decoded) {
+	char *out;
+	int ret;
+
+	if (!SRS_IS_SRS_ADDRESS(rcpt))
+		return (0);
+
+	postfix_srs_init();
+
+	ret = srs_reverse_alloc(srs, &out, rcpt);
+
+	if (ret != SRS_SUCCESS) {
+		switch (SRS_ERROR_TYPE(ret)) {
+			case SRS_ERRTYPE_CONFIG:
+				msg_fatal("SRS configuration error: %s", srs_strerror(ret));
+				return (-1);
+			case SRS_ERRTYPE_INPUT:
+				msg_fatal("SRS reverse failed for <%s>: %s", rcpt, srs_strerror(ret));
+				return (-1);
+			case SRS_ERRTYPE_SYNTAX:
+			case SRS_ERRTYPE_SRS:
+				msg_warn("SRS reverse failed for <%s>: %s", rcpt, srs_strerror(ret));
+				break;
+		}
+		return (0);
+	}
+
+	if (decoded) {
+		*decoded = vstring_alloc(100);
+		vstring_strcpy(*decoded, out);
+	}
+	free(out);
+
+	return (1);
+}
+
+int postfix_srs_forward(const char *sender, const char *alias, VSTRING **encoded) {
+	char *out;
+	int  ret;
+
+	postfix_srs_init();
+
+	ret = srs_forward_alloc(srs, &out, sender, alias);
+	
+	if (ret != SRS_SUCCESS) {
+		msg_warn("SRS forward failed for <%s>: %s", sender, srs_strerror(ret));
+		return (0);
+	}
+	
+	*encoded = vstring_alloc(100);
+	vstring_strcpy(*encoded, out);
+	free(out);
+
+	return (1);
+}
+
+#endif
diff -urN src/qmgr/qmgr_deliver.c.orig src/qmgr/qmgr_deliver.c
--- src/qmgr/qmgr_deliver.c.orig	2012-02-21 14:21:34.000000000 +0100
+++ src/qmgr/qmgr_deliver.c	2012-02-21 14:22:05.000000000 +0100
@@ -76,6 +76,7 @@
 #include <dsn_buf.h>
 #include <dsb_scan.h>
 #include <rcpt_print.h>
+#include <resolve_clnt.h>
 
 /* Application-specific. */
 
@@ -129,6 +130,73 @@
     }
 }
 
+#ifdef HAS_SRS
+/* qmgr_deliver_check_srs - check whether sender should be rewritten */
+
+static int qmgr_deliver_check_srs(QMGR_MESSAGE *message, RECIPIENT_LIST list, char **alias, RESOLVE_REPLY *reply)
+{
+    char *pos;
+
+    /* 
+     * Rewrite if we are not final destination nor relay host for recipient and sender address
+     * it should be enough to look at the first recipient, since transport/nexthop are the same for all recipients
+     */
+    resolve_clnt_query(list.info->address, reply);
+    if (reply->flags & RESOLVE_FLAG_FAIL)
+        return (-1);
+    else if (!(reply->flags & RESOLVE_CLASS_DEFAULT))
+        return (0);
+
+    resolve_clnt_query(message->sender, reply);
+    if (reply->flags & RESOLVE_FLAG_FAIL)
+        return (-1);
+    else if (!(reply->flags & RESOLVE_CLASS_DEFAULT))
+        return (0);
+
+    if (var_srs_domain[0]) {
+        *alias = var_srs_domain;
+    } else {
+        /* retrieve alias domain from original recipient if we are final destination ... */
+        resolve_clnt_query(list.info->orig_addr, reply);
+        if (reply->flags & RESOLVE_FLAG_FAIL)
+            return (-1);
+        if ((reply->flags & RESOLVE_CLASS_FINAL) && (pos = strrchr(list.info->orig_addr, '@'))) {
+            *alias = pos + 1;
+        } else {
+            /* ... or use myorigin as fallback */
+            *alias = var_myorigin;
+        }
+    }
+
+    return (1);
+}
+
+/* qmgr_deliver_do_srs - compute srs address if necessary */
+
+static int qmgr_deliver_do_srs(QMGR_MESSAGE *message, RECIPIENT_LIST list, VSTRING **encoded)
+{
+    RESOLVE_REPLY reply;
+    char *alias;
+    int state;
+
+    resolve_clnt_init(&reply);
+    state = qmgr_deliver_check_srs(message, list, &alias, &reply);
+    resolve_clnt_free(&reply);
+    if (state < 0) {
+        msg_warn("srs lookup problem");
+        return (-1);
+    } else if (state == 0) {
+        return (0);
+    }
+
+    state = postfix_srs_forward(message->sender, alias, encoded);
+    if (state < 0)
+        return (-1);
+
+    return (1);
+}
+#endif
+
 /* qmgr_deliver_send_request - send delivery request to delivery process */
 
 static int qmgr_deliver_send_request(QMGR_ENTRY *entry, VSTREAM *stream)
@@ -140,6 +208,9 @@
     MSG_STATS stats;
     char   *sender;
     int     flags;
+#ifdef HAS_SRS
+    int srs_state;
+#endif
 
     /*
      * If variable envelope return path is requested, change prefix+@origin
@@ -147,7 +218,19 @@
      * recipient per delivery.
      */
     if (message->verp_delims == 0) {
-	sender = message->sender;
+#ifdef HAS_SRS
+        srs_state = qmgr_deliver_do_srs(message, list, &sender_buf);
+        if (srs_state < 0) {
+            return (-1);
+        } else if (srs_state == 1) {
+            sender = vstring_str(sender_buf);
+            msg_info("%s: srs_from=<%s>", message->queue_id, sender);
+        } else {
+            sender = message->sender;
+        }
+#else
+        sender = message->sender;
+#endif
     } else {
 	sender_buf = vstring_alloc(100);
 	verp_sender(sender_buf, message->verp_delims,
diff -urN src/smtpd/smtpd_check.c.orig src/smtpd/smtpd_check.c
--- src/smtpd/smtpd_check.c.orig	2012-02-21 14:21:34.000000000 +0100
+++ src/smtpd/smtpd_check.c	2012-02-21 14:22:05.000000000 +0100
@@ -929,6 +929,19 @@
 	reject_server_error(state);
 }
 
+#ifdef HAS_SRS
+/* check_mail_addr_srs - check if address is a valid srs address */
+
+static int check_mail_addr_srs(SMTPD_STATE *state, const char *reply_name, const char *addr)
+{
+    int result;
+
+    if ((result = postfix_srs_reverse(addr, 0)) < 0)
+        reject_dict_retry(state, reply_name);
+    return (result);
+}
+#endif
+
 /* reject_unknown_reverse_name - fail if reverse client hostname is unknown */
 
 static int reject_unknown_reverse_name(SMTPD_STATE *state)
@@ -4552,6 +4565,13 @@
 	|| MATCH(canonical_maps, CONST_STR(reply->recipient))
 	|| MATCH(virt_alias_maps, CONST_STR(reply->recipient)))
 	return (0);
+	
+#ifdef HAS_SRS
+    /* allow valid srs address */
+    if ((reply->flags & RESOLVE_CLASS_FINAL)
+        && check_mail_addr_srs(state, recipient, CONST_STR(reply->recipient)) == 1)
+        return (0);
+#endif
 
     /*
      * At this point, anything that resolves to the error mailer is known to
