# HG changeset patch # User martin f. krafft # Date 1334154207 -7200 # Node ID 5ec2068d02af2187f5e2d2493c092d76257ec31e # Parent 88466a6ba3ae202aa61c0880a06949ea1f9aa026 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. diff -r 88466a6ba3ae -r 5ec2068d02af README --- 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 ========================== diff -r 88466a6ba3ae -r 5ec2068d02af man/de/man1/vmm.1 --- 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) diff -r 88466a6ba3ae -r 5ec2068d02af man/man1/vmm.1 --- 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) diff -r 88466a6ba3ae -r 5ec2068d02af pgsql/create_tables-dovecot-1.2.x.pgsql --- 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; diff -r 88466a6ba3ae -r 5ec2068d02af pgsql/create_tables.pgsql --- 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; diff -r 88466a6ba3ae -r 5ec2068d02af pgsql/update_tables_0.5.x-0.6-dovecot-1.2.x.pgsql --- 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; diff -r 88466a6ba3ae -r 5ec2068d02af pgsql/update_tables_0.5.x-0.6.pgsql --- 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;