Enable interpolation of alias destinations v0.6.x
authormartin f. krafft <madduck@madduck.net>
Wed, 11 Apr 2012 16:23:27 +0200
branchv0.6.x
changeset 518 5ec2068d02af
parent 517 88466a6ba3ae
child 519 b1fd6f08f369
Enable interpolation of alias destinations This patch modifies the virtual_alias_maps function so that the destination address is parsed for the place holders %n, %d and %=, which are replaced with the localpart, the domain or the full address with '@' replaced by '=' of the queried key. In combination with alias domains, this allows for domain-specific recipients. E.g. given example.org and its alias domain example.com, defining an alias postmaster@example.org → postmaster+%d@example.org will cause mail to postmaster@example.*com* to go to postmaster+example.*com*@example.org.
README
man/de/man1/vmm.1
man/man1/vmm.1
pgsql/create_tables-dovecot-1.2.x.pgsql
pgsql/create_tables.pgsql
pgsql/update_tables_0.5.x-0.6-dovecot-1.2.x.pgsql
pgsql/update_tables_0.5.x-0.6.pgsql
--- a/README	Wed Apr 11 09:08:19 2012 +0200
+++ b/README	Wed Apr 11 16:23:27 2012 +0200
@@ -61,6 +61,13 @@
 
   ‣ supports multiple destinations per e-mail alias
   ‣ destinations can be deleted separately
+  ‣ destinations can be interpolated using the original address' localpart
+    and domain, allowing aliases to have different meaning in aliasdomains,
+    e.g. with the following defined in example.org:
+      postmaster@example.org  →  postmaster+%d@admin.example.org
+    If example.com is an aliasdomain of example.org, the alias will become
+      postmaster@example.org  →  postmaster+example.org@admin.example.org
+      postmaster@example.com  →  postmaster+example.com@admin.example.org
 
 Installation Prerequisites
 ==========================
--- a/man/de/man1/vmm.1	Wed Apr 11 09:08:19 2012 +0200
+++ b/man/de/man1/vmm.1	Wed Apr 11 16:23:27 2012 +0200
@@ -780,11 +780,21 @@
 .IR destination (en),
 erstellt.
 .PP
+Innerhalb der Zieladresse werden die Zeichenketten
+.IR %n ,
+.IR %d
+und
+.IR %=
+durch den ursprünglichen lokalen Teil, die Domain bzw. die Emailadresse mit
+'=' anstelle von '@' ersetzt. Dies ermöglicht z.B. in Verbindung mit
+Alias-Domains domain-spezifische Empfänger.
+.PP
 Beispiele:
 .PP
 .nf
 .B vmm aliasadd john.doe@example.com d.user@example.com
 .B vmm aa support@example.com d.user@example.com e.user@example.com
+.B vmm aa postmaster@example.com postmaster+%d@example.org
 .fi
 .\" ------------------------------------
 .SS aliasdelete (ad)
--- a/man/man1/vmm.1	Wed Apr 11 09:08:19 2012 +0200
+++ b/man/man1/vmm.1	Wed Apr 11 16:23:27 2012 +0200
@@ -746,11 +746,21 @@
 .I destination
 addresses.
 .PP
+Within the destination address, the placeholders
+.IR %n ,
+.IR %d ,
+and
+.IR %=
+will be replaced by the local part, the domain, or the email address with '@'
+replaced by '=' respectively. In combination with alias domains, this enables
+domain-specific destinations.
+.PP
 Examples:
 .PP
 .nf
 .B vmm aliasadd john.doe@example.com d.user@example.com
 .B vmm aa support@example.com d.user@example.com e.user@example.com
+.B vmm aa postmaster@example.com postmaster+%d@example.org
 .fi
 .\" ------------------------------------
 .SS aliasdelete (ad)
--- a/pgsql/create_tables-dovecot-1.2.x.pgsql	Wed Apr 11 09:08:19 2012 +0200
+++ b/pgsql/create_tables-dovecot-1.2.x.pgsql	Wed Apr 11 16:23:27 2012 +0200
@@ -584,6 +584,25 @@
 --
 -- For more details see postconf(5) section virtual_alias_maps and virtual(5)
 -- ---
+CREATE OR REPLACE FUNCTION _interpolate_destination(
+    IN destination varchar, localpart varchar, IN the_domain varchar)
+    RETURNS varchar
+AS $$
+    DECLARE
+        result varchar(320);
+    BEGIN
+        IF position('%' in destination) = 0 THEN
+            RETURN destination;
+        END IF;
+        result := replace(destination, '%n', localpart);
+        result := replace(result, '%d', the_domain);
+        result := replace(result, '%=', localpart || '=' || the_domain);
+        RETURN result;
+    END;
+$$ LANGUAGE plpgsql STABLE
+RETURNS NULL ON NULL INPUT
+EXTERNAL SECURITY INVOKER;
+
 CREATE OR REPLACE FUNCTION postfix_virtual_alias_map(
     IN localpart varchar, IN the_domain varchar)
     RETURNS SETOF recipient_destination
@@ -596,7 +615,8 @@
         did bigint := (SELECT gid FROM domain_name WHERE domainname=the_domain);
     BEGIN
         FOR record IN
-            SELECT recipient, destination
+            SELECT recipient,
+                _interpolate_destination(destination, localpart, the_domain)
               FROM alias
              WHERE gid = did
                AND address = localpart
@@ -614,7 +634,8 @@
             -- or relocated entry and return the identity mapping if that is
             -- the case
             OPEN catchall_cursor FOR
-                SELECT recipient, destination
+                SELECT recipient,
+                    _interpolate_destination(destination, localpart, the_domain)
                   FROM catchall
                  WHERE gid = did;
             FETCH NEXT FROM catchall_cursor INTO recordc;
--- a/pgsql/create_tables.pgsql	Wed Apr 11 09:08:19 2012 +0200
+++ b/pgsql/create_tables.pgsql	Wed Apr 11 16:23:27 2012 +0200
@@ -561,6 +561,25 @@
 --
 -- For more details see postconf(5) section virtual_alias_maps and virtual(5)
 -- ---
+CREATE OR REPLACE FUNCTION _interpolate_destination(
+    IN destination varchar, localpart varchar, IN the_domain varchar)
+    RETURNS varchar
+AS $$
+    DECLARE
+        result varchar(320);
+    BEGIN
+        IF position('%' in destination) = 0 THEN
+            RETURN destination;
+        END IF;
+        result := replace(destination, '%n', localpart);
+        result := replace(result, '%d', the_domain);
+        result := replace(result, '%=', localpart || '=' || the_domain);
+        RETURN result;
+    END;
+$$ LANGUAGE plpgsql STABLE
+RETURNS NULL ON NULL INPUT
+EXTERNAL SECURITY INVOKER;
+
 CREATE OR REPLACE FUNCTION postfix_virtual_alias_map(
     IN localpart varchar, IN the_domain varchar)
     RETURNS SETOF recipient_destination
@@ -573,7 +592,8 @@
         did bigint := (SELECT gid FROM domain_name WHERE domainname=the_domain);
     BEGIN
         FOR record IN
-            SELECT recipient, destination
+            SELECT recipient,
+                _interpolate_destination(destination, localpart, the_domain)
               FROM alias
              WHERE gid = did
                AND address = localpart
@@ -591,7 +611,8 @@
             -- or relocated entry and return the identity mapping if that is
             -- the case
             OPEN catchall_cursor FOR
-                SELECT recipient, destination
+                SELECT recipient,
+                    _interpolate_destination(destination, localpart, the_domain)
                   FROM catchall
                  WHERE gid = did;
             FETCH NEXT FROM catchall_cursor INTO recordc;
--- a/pgsql/update_tables_0.5.x-0.6-dovecot-1.2.x.pgsql	Wed Apr 11 09:08:19 2012 +0200
+++ b/pgsql/update_tables_0.5.x-0.6-dovecot-1.2.x.pgsql	Wed Apr 11 16:23:27 2012 +0200
@@ -481,6 +481,25 @@
 --      varchar the_domain
 -- Returns: recipient_destination records
 -- ---
+CREATE OR REPLACE FUNCTION _interpolate_destination(
+    IN destination varchar, localpart varchar, IN the_domain varchar)
+    RETURNS varchar
+AS $$
+    DECLARE
+        result varchar(320);
+    BEGIN
+        IF position('%' in destination) = 0 THEN
+            RETURN destination;
+        END IF;
+        result := replace(destination, '%n', localpart);
+        result := replace(result, '%d', the_domain);
+        result := replace(result, '%=', localpart || '=' || the_domain);
+        RETURN result;
+    END;
+$$ LANGUAGE plpgsql STABLE
+RETURNS NULL ON NULL INPUT
+EXTERNAL SECURITY INVOKER;
+
 CREATE OR REPLACE FUNCTION postfix_virtual_alias_map(
     IN localpart varchar, IN the_domain varchar)
     RETURNS SETOF recipient_destination
@@ -493,7 +512,8 @@
         did bigint := (SELECT gid FROM domain_name WHERE domainname=the_domain);
     BEGIN
         FOR record IN
-            SELECT recipient, destination
+            SELECT recipient,
+                _interpolate_destination(destination, localpart, the_domain)
               FROM alias
              WHERE gid = did
                AND address = localpart
@@ -511,7 +531,8 @@
             -- or relocated entry and return the identity mapping if that is
             -- the case
             OPEN catchall_cursor FOR
-                SELECT recipient, destination
+                SELECT recipient,
+                    _interpolate_destination(destination, localpart, the_domain)
                   FROM catchall
                  WHERE gid = did;
             FETCH NEXT FROM catchall_cursor INTO recordc;
--- a/pgsql/update_tables_0.5.x-0.6.pgsql	Wed Apr 11 09:08:19 2012 +0200
+++ b/pgsql/update_tables_0.5.x-0.6.pgsql	Wed Apr 11 16:23:27 2012 +0200
@@ -459,6 +459,25 @@
 --      varchar the_domain
 -- Returns: recipient_destination records
 -- ---
+CREATE OR REPLACE FUNCTION _interpolate_destination(
+    IN destination varchar, localpart varchar, IN the_domain varchar)
+    RETURNS varchar
+AS $$
+    DECLARE
+        result varchar(320);
+    BEGIN
+        IF position('%' in destination) = 0 THEN
+            RETURN destination;
+        END IF;
+        result := replace(destination, '%n', localpart);
+        result := replace(result, '%d', the_domain);
+        result := replace(result, '%=', localpart || '=' || the_domain);
+        RETURN result;
+    END;
+$$ LANGUAGE plpgsql STABLE
+RETURNS NULL ON NULL INPUT
+EXTERNAL SECURITY INVOKER;
+
 CREATE OR REPLACE FUNCTION postfix_virtual_alias_map(
     IN localpart varchar, IN the_domain varchar)
     RETURNS SETOF recipient_destination
@@ -471,7 +490,8 @@
         did bigint := (SELECT gid FROM domain_name WHERE domainname=the_domain);
     BEGIN
         FOR record IN
-            SELECT recipient, destination
+            SELECT recipient,
+                _interpolate_destination(destination, localpart, the_domain)
               FROM alias
              WHERE gid = did
                AND address = localpart
@@ -489,7 +509,8 @@
             -- or relocated entry and return the identity mapping if that is
             -- the case
             OPEN catchall_cursor FOR
-                SELECT recipient, destination
+                SELECT recipient,
+                    _interpolate_destination(destination, localpart, the_domain)
                   FROM catchall
                  WHERE gid = did;
             FETCH NEXT FROM catchall_cursor INTO recordc;