Mailing List Archive

Saving the variable part of local part suffixes
Hello,

last year, Philip and me spoke about how to obtain the part of
a local part suffix that is matched by "*". With the address
"address-subaddress@domain" and local_part_suffix = "-*" you get:

$local_part is address
$local_part_suffix is -subaddress
$local_part_subaddress is subaddress (no -)

Looks easy without an Exim patch, but if local_part_suffix is set to
use multiple strings or if different routers use multiple ones, there
is no easy way to know what to strip from $local_part_suffix to get the
subaddress, so the subaddress really needs to be held in the address_item.
The subaddress is required in order to implement the Sieve subaddress
extension, but it would also make some Exim configurations easier.
We did not hack the code, because there was some subtle problem, that
I unfortunately forgot by now.

The patch below is not tested and please do not commit it. I would
be glad if you could just have a look at it and tell me if there is
something obvious I forgot or screwed up. I just can't remember what
stopped us last year from an easy hack like this.

Michael
----------------------------------------------------------------------
--- src/structs.h.orig 2005-03-01 11:22:08.000000000 +0100
+++ src/structs.h 2005-03-08 16:57:15.000000000 +0100
@@ -248,6 +248,7 @@
uschar *self; /* Text option for handling self reference */
uschar *senders; /* Specific senders */
uschar *suffix; /* Address suffix */
+ uschar *subaddress; /* Subaddress */
uschar *translate_ip_address; /* IP address translation fudgery */
uschar *transport_name; /* Transport name */

@@ -531,6 +532,7 @@
uschar *local_part; /* points to cc or lc version */
uschar *prefix; /* stripped prefix of local part */
uschar *suffix; /* stripped suffix of local part */
+ uschar *subaddress; /* stripped suffix of local part */
uschar *domain; /* working domain (lower cased) */

uschar *address_retry_key; /* retry key including full address */
--- src/route.c.orig 2005-03-08 16:00:41.000000000 +0100
+++ src/route.c 2005-03-08 16:39:41.000000000 +0100
@@ -353,10 +353,11 @@
suffixes the list of suffixes

Returns: length of matching suffix or zero
+ subaddress length of matched subaddress or zero
*/

int
-route_check_suffix(uschar *local_part, uschar *suffixes)
+route_check_suffix(uschar *local_part, uschar *suffixes, int *subaddress)
{
int sep = 0;
int alen = Ustrlen(local_part);
@@ -373,13 +374,21 @@
uschar *p, *pend;
pend = local_part + alen - (--slen) + 1;
for (p = local_part; p < pend; p++)
- if (strncmpic(suffix, p, slen) == 0) return alen - (p - local_part);
+ if (strncmpic(suffix, p, slen) == 0)
+ {
+ if (subaddress) *subaddress = alen - (p + slen - local_part);
+ return alen - (p - local_part);
+ }
}
else
if (alen > slen && strncmpic(suffix, local_part + alen - slen, slen) == 0)
+ {
+ if (subaddress) *subaddress = 0;
return slen;
+ }
}

+if (subaddress) *subaddress = 0;
return 0;
}

@@ -1593,11 +1602,13 @@

if (r->suffix != NULL)
{
- int slen = route_check_suffix(addr->local_part, r->suffix);
+ int salen,slen = route_check_suffix(addr->local_part, r->suffix, &salen);
if (slen > 0)
{
- int lplen = Ustrlen(addr->local_part) - slen;
+ int olplen = Ustrlen(addr->local_part);
+ int lplen = olplen - slen;
addr->suffix = addr->local_part + lplen;
+ addr->subaddress = addr->local_part + olplen - salen;
addr->local_part = string_copyn(addr->local_part, lplen);
DEBUG(D_route) debug_printf("stripped suffix %s\n", addr->suffix);
}
--- src/receive.c.orig 2005-03-08 16:32:25.000000000 +0100
+++ src/receive.c 2005-03-08 16:35:00.000000000 +0100
@@ -2292,7 +2292,7 @@

if (at != NULL) *at = 0;
from_address += route_check_prefix(from_address, local_from_prefix);
- slen = route_check_suffix(from_address, local_from_suffix);
+ slen = route_check_suffix(from_address, local_from_suffix, (int*)0);
if (slen > 0)
{
memmove(from_address+slen, from_address, Ustrlen(from_address)-slen);
--- src/functions.h.orig 2005-03-08 16:29:39.000000000 +0100
+++ src/functions.h 2005-03-08 16:29:51.000000000 +0100
@@ -221,7 +221,7 @@
extern int route_address(address_item *, address_item **, address_item **,
address_item **, address_item **, int);
extern int route_check_prefix(uschar *, uschar *);
-extern int route_check_suffix(uschar *, uschar *);
+extern int route_check_suffix(uschar *, uschar *, int *);
extern BOOL route_findgroup(uschar *, gid_t *);
extern BOOL route_finduser(uschar *, struct passwd **, uid_t *);
extern BOOL route_find_expanded_group(uschar *, uschar *, uschar *, gid_t *,
--- src/globals.h.orig 2005-03-08 16:50:45.000000000 +0100
+++ src/globals.h 2005-03-08 16:50:39.000000000 +0100
@@ -241,6 +241,7 @@
extern uschar *deliver_localpart_parent; /* The parent local part for delivery */
extern uschar *deliver_localpart_prefix; /* The stripped prefix, if any */
extern uschar *deliver_localpart_suffix; /* The stripped suffix, if any */
+extern uschar *deliver_localpart_subaddress; /* The stripped subaddress, if any */
extern BOOL deliver_force_thaw; /* TRUE to force thaw in queue run */
extern BOOL deliver_manual_thaw; /* TRUE if manually thawed */
extern uschar *deliver_out_buffer; /* Buffer for copying file */
--- src/globals.c.orig 2005-03-01 11:22:08.000000000 +0100
+++ src/globals.c 2005-03-08 16:49:14.000000000 +0100
@@ -142,6 +142,7 @@
&deliver_localpart_parent,
&deliver_localpart_prefix,
&deliver_localpart_suffix,
+ &deliver_localpart_subaddress,
(uschar **)(&deliver_recipients),
&deliver_host,
&deliver_home,
@@ -244,6 +245,7 @@
NULL, /* local_part */
NULL, /* prefix */
NULL, /* suffix */
+ NULL, /* subaddress */
NULL, /* domain */
NULL, /* address_retry_key */
NULL, /* domain_retry_key */
@@ -447,6 +454,7 @@
uschar *deliver_localpart_parent = NULL;
uschar *deliver_localpart_prefix = NULL;
uschar *deliver_localpart_suffix = NULL;
+uschar *deliver_localpart_subaddress = NULL;
BOOL deliver_force_thaw = FALSE;
BOOL deliver_manual_thaw = FALSE;
uschar *deliver_out_buffer = NULL;
@@ -872,6 +880,7 @@
US"freeze", /* self */
NULL, /* senders */
NULL, /* suffix */
+ NULL, /* subaddress */
NULL, /* translate_ip_address */
NULL, /* transport_name */

--- src/macros.h.orig 2005-03-08 16:52:58.000000000 +0100
+++ src/macros.h 2005-03-08 16:53:07.000000000 +0100
@@ -101,7 +101,7 @@
verifying. This has to be explicit because it is referenced in more than one
source module. */

-#define ADDRESS_EXPANSIONS_COUNT 18
+#define ADDRESS_EXPANSIONS_COUNT 19

/* The maximum permitted number of command-line (-D) macro definitions. We
need a limit only to make it easier to generate argument vectors for re-exec
--- src/expand.c.orig 2005-03-08 17:02:13.000000000 +0100
+++ src/expand.c 2005-03-08 17:02:41.000000000 +0100
@@ -364,6 +364,7 @@
{ "local_part_data", vtype_stringptr, &deliver_localpart_data },
{ "local_part_prefix", vtype_stringptr, &deliver_localpart_prefix },
{ "local_part_suffix", vtype_stringptr, &deliver_localpart_suffix },
+ { "local_part_subaddress", vtype_stringptr, &deliver_localpart_subaddress },
{ "local_scan_data", vtype_stringptr, &local_scan_data },
{ "local_user_gid", vtype_gid, &local_user_gid },
{ "local_user_uid", vtype_uid, &local_user_uid },
Re: Saving the variable part of local part suffixes [ In reply to ]
On Thu, 10 Mar 2005, Michael Haardt wrote:

> The patch below is not tested and please do not commit it. I would
> be glad if you could just have a look at it and tell me if there is
> something obvious I forgot or screwed up. I just can't remember what
> stopped us last year from an easy hack like this.

I will look at it, but not for some days. I suspect, however, that what
bothered me was the increase in size of the address_item structure,
because it's quite big already and I'm wary about making it bigger.
There is no problem for a message with only a few recipients, but people
have mailing lists that expand into thousands of addresses, in which
case each increase uses 1000s times the memory increase. But maybe I'm
too paranoid.

At one point I also had a long-term plan not to copy these values into
separate expansion variables, but to have a new type that picked the
data out of an address_item structure. But I've never got round to doing
that.

One other comment: your patch appears to cope only with suffixes. Any
such change must also handle prefixes, for consistency.


--
Philip Hazel University of Cambridge Computing Service,
ph10@cus.cam.ac.uk Cambridge, England. Phone: +44 1223 334714.
Get the Exim 4 book: http://www.uit.co.uk/exim-book
Re: Saving the variable part of local part suffixes [ In reply to ]
> I will look at it, but not for some days. I suspect, however, that what
> bothered me was the increase in size of the address_item structure,
> because it's quite big already and I'm wary about making it bigger.
> There is no problem for a message with only a few recipients, but people
> have mailing lists that expand into thousands of addresses, in which
> case each increase uses 1000s times the memory increase. But maybe I'm
> too paranoid.

The patch would add one pointer to an already allocated string, so 1000
addresses would allocate about a page more on typical 32-bit systems.

> One other comment: your patch appears to cope only with suffixes. Any
> such change must also handle prefixes, for consistency.

I saw postmasters use prefixes for all kinds of things, but what users
know by "subaddressing" always uses a separator between the user part
on the left and a subaddress on the right.

Do you want to add a variable that contains the "*"-matched part of
a prefix? That's more than a pointer, I think. ;-)

Michael
Re: Saving the variable part of local part suffixes [ In reply to ]
On Mon, 14 Mar 2005, Michael Haardt wrote:

> The patch would add one pointer to an already allocated string, so 1000
> addresses would allocate about a page more on typical 32-bit systems.

I haven't checked up on this, it may be more than one pointer. I can't
remember if there's an "original case" and a lowercased version, as
there is for the local part itself. And we must do both prefix and
suffix. Otherwise the specification is too baroque, because all other
things that are concerned with prefixes and suffixes work for both.


--
Philip Hazel University of Cambridge Computing Service,
ph10@cus.cam.ac.uk Cambridge, England. Phone: +44 1223 334714.
Get the Exim 4 book: http://www.uit.co.uk/exim-book
Re: Saving the variable part of local part suffixes [ In reply to ]
On Mon, 2005-03-14 at 14:22 +0000, Philip Hazel wrote:
> On Mon, 14 Mar 2005, Michael Haardt wrote:
>
> > The patch would add one pointer to an already allocated string, so 1000
> > addresses would allocate about a page more on typical 32-bit systems.
>
> I haven't checked up on this, it may be more than one pointer. I can't
> remember if there's an "original case" and a lowercased version, as
> there is for the local part itself. And we must do both prefix and
> suffix. Otherwise the specification is too baroque, because all other
> things that are concerned with prefixes and suffixes work for both.

Prefix can't be done as a pointer - it would point to the start of the
string. We might well do better to save an unsigned short offset to the
start of the suffix, and the length of the prefix. If its worth doing
at all.

Nigel.

--
[ Nigel Metheringham Nigel.Metheringham@InTechnology.co.uk ]
[. - Comments in this message are my own and not ITO opinion/policy - ]
Re: Saving the variable part of local part suffixes [ In reply to ]
On 3/14/2005 4:46, "Michael Haardt" <michael@freenet-ag.de> wrote:

> I saw postmasters use prefixes for all kinds of things, but what users
> know by "subaddressing" always uses a separator between the user part
> on the left and a subaddress on the right.

Not here...we use a prefix (dodging the plural form here ;-) with a .
Separator.

Unfortunately, a suitable URL isn't directly available for our
documentation...go here:

http://www.olympus.net/

And in the second column from the left, click documentation under
AccountManager. Then search for
prefix

However, we manage and process these addresses outside of Exim (the code
then tells Exim where to deliver the message)...we have nothing about prefix
in the Exim configurations.

--John
Re: Saving the variable part of local part suffixes [ In reply to ]
On 3/15/2005 2:35, "Michael Haardt" <michael@freenet-ag.de> wrote:

>>> I saw postmasters use prefixes for all kinds of things, but what users
>>> know by "subaddressing" always uses a separator between the user part
>>> on the left and a subaddress on the right.
>>
>> Not here...we use a prefix (dodging the plural form here ;-) with a .
>> Separator.
>
> Although I thought, if anybody used prefixes, he will probably object,
> I didn't expect to see an answer.
>
>> Unfortunately, a suitable URL isn't directly available for our
>> documentation...go here:
>>
>> http://www.olympus.net/
>>
>> And in the second column from the left, click documentation under
>> AccountManager. Then search for
>> prefix
>
> All I get is:
>
> ----------------------------------------------------------------------
> Errors are:


That's odd, Michael, and thanks for the report. I have passed it along.
The search worked while I was preparing the message for the list.

Fortunately, there is an alternate route:

go here:

http://www.olympus.net/

And in the second column from the left, click documentation under
AccountManager. (Same as before so far)

In the left column, click AccountManager User Manual.

In the Contents, click a. Prefix Mail Aliases under 2. Mail Aliases under
C. Mail Tools.


>> However, we manage and process these addresses outside of Exim (the code
>> then tells Exim where to deliver the message)...we have nothing about prefix
>> in the Exim configurations.
>
> Could you tell me some examples? This may be very interesting to the
> Sieve mailing list.

Well, when I register a product with a vendor I haven't used before, I
create a vendor-specific prefix mail alias...something like
xxx.jwbaxter@olympus.net
(which example I haven't defined, so it will bounce). I use AccountManager
to define the alias--before completing the registration, as some vendors are
now checking the offered address before letting one proceed through the
form.

If I want to, I can define xxx.jwbaxter@olympus.net with a limited lifetime,
and AccountManager will then automatically remove it.

When the address is defined in AccountManager, one of the actions is to add
it as an address in our MySQL database...that way Exim knows to accept it.
The message like other incoming messages is handed off to our mail processor
system, which deals with the prefix (and any sorting or forwarding that it
may trigger). Once the message is handed back to Exim, it is addressed to
jwbaxter@olympus.net (unless forwarded somewhere else).

--John
Re: Saving the variable part of local part suffixes [ In reply to ]
> > I saw postmasters use prefixes for all kinds of things, but what users
> > know by "subaddressing" always uses a separator between the user part
> > on the left and a subaddress on the right.
>
> Not here...we use a prefix (dodging the plural form here ;-) with a .
> Separator.

So one counterexample proved me wrong. Ok, so now we have people using
subaddresses as prefix and as suffix. Anybody who does both? :)

Do we need local_part_prefix_subaddress and local_part_suffix_subaddress
or just local_part_subaddress, that contains both of it and allows to
reference it however the system is configured?

Michael
Re: Saving the variable part of local part suffixes [ In reply to ]
> Prefix can't be done as a pointer - it would point to the start of the
> string. We might well do better to save an unsigned short offset to the
> start of the suffix, and the length of the prefix. If its worth doing
> at all.

We do need something that can be referenced as string variable, so
offset/length is not enough.

The more I get into this, the more I think an abstraction from the
prefixes is a good idea. A system may even allow different ways of
subaddressing, so filters should be able just to refer to a subaddress,
no matter how it is encoded in mail addresses.

Michael
Re: Saving the variable part of local part suffixes [ In reply to ]
On Wed, 16 Mar 2005, Michael Haardt wrote:

> The more I get into this, the more I think an abstraction from the
> prefixes is a good idea. A system may even allow different ways of
> subaddressing, so filters should be able just to refer to a subaddress,
> no matter how it is encoded in mail addresses.

You see why I was trying to leave this alone? :-)) Looks like a better
approach is needed, but designing that requires time, which I do not
have much of just at the moment.

--
Philip Hazel University of Cambridge Computing Service,
ph10@cus.cam.ac.uk Cambridge, England. Phone: +44 1223 334714.
Get the Exim 4 book: http://www.uit.co.uk/exim-book
Re: Saving the variable part of local part suffixes [ In reply to ]
Michael Haardt <michael@freenet-ag.de> wrote:

> Ok, so now we have people using subaddresses as prefix and as suffix.
> Anybody who does both? :)

I do. See the From: field. I use a prefix subaddress (delimited by
dot) for a meaningful subdivision of my mailbox, and a suffix subaddress
(delimited by plus) for a meaningless variant, so that I can disable the
address if it becomes known to spammers, and start using a new suffix
without having to update any filters I might have set up based on the
prefix.

Prefix subaddresses are consistent with the overall little-endian
order of email addresses, and suffix subaddresses visually bury the
subaddress; therefore prefixes and suffixes are are well suited for
meaningful and meaningless subaddresses, respectively.

My outgoing non-list mail is From: amc+randomstring+@... with a new
random suffix for each message, but for list mail I reuse a non-random
suffix to play nice with permission-to-post mechanisms based on the
sender address.

AMC
Re: Saving the variable part of local part suffixes [ In reply to ]
On Wed, Mar 16, 2005 at 09:18:12PM +0000, Adam M. Costello wrote:
> Michael Haardt <michael@freenet-ag.de> wrote:
>
> > Ok, so now we have people using subaddresses as prefix and as suffix.
> > Anybody who does both? :)
>
> I do.
> [explaination removed]

Thanks for your reply! It pretty much destroys the concept of
automatically extracting the subaddress.

I suggest a different aproach now: A new router option, like
sieve_vacation_directory, named local_part_subaddress, that is available
as variable in Exim filters and as subaddress extension in Sieve. Since
it is a router option, no change to the address_item is needed. (Philip
will be glad to read that.:-)

That way, admins can use whatever string expression they like to compose
the subaddress. It is set at the same place prefixes are set and just
as flexible as my previous suggestion.

Michael
Re: Saving the variable part of local part suffixes [ In reply to ]
> I suggest a different aproach now: A new router option, like
> sieve_vacation_directory, named local_part_subaddress, that is available
> as variable in Exim filters and as subaddress extension in Sieve. Since
> it is a router option, no change to the address_item is needed. (Philip
> will be glad to read that.:-)

In fact, two new router options. I am not sure if this is interesting
to Exim filters, because Exim filters could contain the string expression
right away, so I did not add new variables. Opinions?

I append an experimental patch against the 4.51 snapshot, in case anybody
wants to play with it. The two new router options are sieve_subaddress
and sieve_useraddress. A common example may be:

local_part_suffix = "-*"
local_part_suffix_optional
sieve_subaddress = "${sg{$local_part_suffix}{^-}{}}"
sieve_useraddress = "$local_part"

This patch also contains the patch to allow using the vacation extension
when testing filters, but not yet code to allow the subaddress extension
in filters.

My current suggestion for the documentation is:

The extension "subaddress" is specified using the following grammar
extension.

address-part =/ ":user" / ":detail"

RFC 3598 uses the model of a user part, followed by a separator character
and the subaddress. In the real world, subaddresses are encoded in a
number different ways, so this implementation relies entirely on Exim
to set user and detail from the envelope "to" address, thus moving from
syntactic sugar to a real abstraction.

RFC 3598 allows to check other addresses than the envelope "to" address.
There is a pretty good chance to get wrong results by applying the
encoding rules for the currently processed envelope "to" address to other
addresses. If processing other addresses, this implementation always
uses the local part for :user and any test concerning :detail will be false.

Michael
----------------------------------------------------------------------
--- src/rda.c.orig 2005-03-01 11:22:08.000000000 +0100
+++ src/rda.c 2005-03-17 11:11:59.000000000 +0100
@@ -333,6 +333,8 @@
options the options bits
include_directory restrain to this directory
sieve_vacation_directory passed to sieve_interpret
+ useraddress passed to sieve_interpret
+ subaddress passed to sieve_interpret
generated where to hang generated addresses
error for error messages
eblockp for details of skipped syntax errors
@@ -348,7 +350,7 @@

static int
rda_extract(redirect_block *rdata, int options, uschar *include_directory,
- uschar *sieve_vacation_directory, address_item **generated, uschar **error,
+ uschar *sieve_vacation_directory, uschar *useraddress, uschar *subaddress, address_item **generated, uschar **error,
error_block **eblockp, int *filtertype)
{
uschar *data;
@@ -407,7 +409,7 @@
*error = US"Sieve filtering not enabled";
return FF_ERROR;
}
- frc = sieve_interpret(data, options, sieve_vacation_directory, generated,
+ frc = sieve_interpret(data, options, sieve_vacation_directory, useraddress, subaddress, generated,
error);
}

@@ -515,6 +517,8 @@
plus ENOTDIR and EACCES handling bits
include_directory restrain :include: to this directory
sieve_vacation_directory directory passed to sieve_interpret()
+ useraddress user address string expression
+ subaddress subaddress string expression
ugid uid/gid to run under - if NULL, no change
generated where to hang generated addresses, initially NULL
error pointer for error message
@@ -541,7 +545,7 @@

int
rda_interpret(redirect_block *rdata, int options, uschar *include_directory,
- uschar *sieve_vacation_directory, ugid_block *ugid, address_item **generated,
+ uschar *sieve_vacation_directory, uschar *useraddress, uschar *subaddress, ugid_block *ugid, address_item **generated,
uschar **error, error_block **eblockp, int *filtertype, uschar *rname)
{
int fd, rc, pfd[2];
@@ -586,7 +590,7 @@
Ustrstr(data, ":include:") == NULL)) /* and there's no :include: */
{
return rda_extract(rdata, options, include_directory,
- sieve_vacation_directory, generated, error, eblockp, filtertype);
+ sieve_vacation_directory, useraddress, subaddress, generated, error, eblockp, filtertype);
}

/* We need to run the processing code in a sub-process. However, if we can
@@ -631,7 +635,7 @@
/* Now do the business */

yield = rda_extract(rdata, options, include_directory,
- sieve_vacation_directory, generated, error, eblockp, filtertype);
+ sieve_vacation_directory, useraddress, subaddress, generated, error, eblockp, filtertype);

/* Pass back whether it was a filter, and the return code and any overall
error text via the pipe. */
--- src/sieve.c.rel 2005-03-10 12:31:01.000000000 +0100
+++ src/sieve.c 2005-03-17 12:36:17.000000000 +0100
@@ -4,7 +4,7 @@
* Exim - an Internet mail transport agent *
*************************************************/

-/* Copyright (c) Michael Haardt 2003,2004 */
+/* Copyright (c) Michael Haardt 2003-2005 */
/* See the file NOTICE for conditions of use and distribution. */

/* This code was contributed by Michael Haardt. */
@@ -29,8 +29,9 @@
#undef RFC_EOL

/* Define this for development of the subaddress Sieve extension. */
-/* The code is currently broken. */
-#undef SUBADDRESS
+/* The code is currently broken, because it can not split addresses */
+/* in headers into user and detail. */
+#define SUBADDRESS

/* Define this for the vacation Sieve extension. */
#define VACATION
@@ -64,6 +65,8 @@
int vacation_ran;
#endif
uschar *vacation_directory;
+ const uschar *subaddress;
+ const uschar *useraddress;
int require_copy;
int require_iascii_numeric;
};
@@ -1723,10 +1726,8 @@
case ADDRPART_LOCALPART: part=extracted_addr; part[domain-1]='\0'; break;
case ADDRPART_DOMAIN: part=extracted_addr+domain; break;
#ifdef SUBADDRESS
- case ADDRPART_DETAIL:
- part=NULL;
+ case ADDRPART_DETAIL: part=NULL; break;
#endif
- break;
}

*end_addr = saveend;
@@ -2031,9 +2032,7 @@
case ADDRPART_LOCALPART: envelopeExpr=CUS "${local_part:$sender_address}"; break;
case ADDRPART_DOMAIN: envelopeExpr=CUS "${domain:$sender_address}"; break;
#ifdef SUBADDRESS
- case ADDRPART_DETAIL:
- envelopeExpr=CUS 0;
- break;
+ case ADDRPART_DETAIL: envelopeExpr=CUS 0; break;
#endif
}
}
@@ -2043,8 +2042,8 @@
{
case ADDRPART_ALL: envelopeExpr=CUS "$local_part_prefix$local_part$local_part_suffix@$domain"; break;
#ifdef SUBADDRESS
- case ADDRPART_USER: envelopeExpr=CUS "$local_part_prefix$local_part"; break;
- case ADDRPART_DETAIL: envelopeExpr=CUS "$local_part_suffix"; break;
+ case ADDRPART_USER: envelopeExpr=filter->useraddress; break;
+ case ADDRPART_DETAIL: envelopeExpr=filter->subaddress; break;
#endif
case ADDRPART_LOCALPART: envelopeExpr=CUS "$local_part_prefix$local_part$local_part_suffix"; break;
case ADDRPART_DOMAIN: envelopeExpr=CUS "$domain"; break;
@@ -2517,10 +2516,12 @@

if (filter_personal(aliases,TRUE))
{
+ if (filter_test == FTEST_NONE)
+ {
+ /* ensure oncelog directory exists; failure will be detected later */

- /* ensure oncelog directory exists; failure will be detected later */
-
- (void)directory_make(NULL, filter->vacation_directory, 0700, FALSE);
+ (void)directory_make(NULL, filter->vacation_directory, 0700, FALSE);
+ }

/* build oncelog filename */

@@ -2538,88 +2539,99 @@
md5_start(&base);
md5_end(&base, key.character, key.length, digest);
for (i = 0; i < 16; i++) sprintf(CS (hexdigest+2*i), "%02X", digest[i]);
- capacity=Ustrlen(filter->vacation_directory);
- start=capacity;
- once=string_cat(filter->vacation_directory,&capacity,&start,US"/",1);
- once=string_cat(once,&capacity,&start,hexdigest,33);
- once[start] = '\0';
-
- /* process subject */
-
- if (subject.length==-1)
- {
- expand_header(&subject,&str_subject);
- while (subject.length>=4 && Ustrncmp(subject.character,"Re: ",4)==0)
- {
- subject.character+=4;
- subject.length-=4;
- }
- capacity=6;
- start=6;
- subject.character=string_cat(US"Auto: ",&capacity,&start,subject.character,subject.length);
- subject.length=start;
- }
-
- /* add address to list of generated addresses */
-
- addr = deliver_make_addr(string_sprintf(">%.256s", sender_address), FALSE);
- setflag(addr, af_pfr);
- setflag(addr, af_ignore_error);
- addr->next = *generated;
- *generated = addr;
- addr->reply = store_get(sizeof(reply_item));
- memset(addr->reply,0,sizeof(reply_item)); /* XXX */
- addr->reply->to = string_copy(sender_address);
- addr->reply->from = expand_string(US"$local_part@$domain");
- /* Allocation is larger than neccessary, but enough even for split MIME words */
- buffer_capacity=16+4*subject.length;
- buffer=store_get(buffer_capacity);
- addr->reply->subject=parse_quote_2047(subject.character, subject.length, US"utf-8", buffer, buffer_capacity);
- addr->reply->oncelog=once;
- addr->reply->once_repeat=days*86400;
+ if (filter_test != FTEST_NONE)
+ {
+ debug_printf("Sieve: mail was personal, vacation file basename: %s\n", hexdigest);
+ }
+ else
+ {
+ capacity=Ustrlen(filter->vacation_directory);
+ start=capacity;
+ once=string_cat(filter->vacation_directory,&capacity,&start,US"/",1);
+ once=string_cat(once,&capacity,&start,hexdigest,33);
+ once[start] = '\0';

- /* build body and MIME headers */
+ /* process subject */

- if (reason_is_mime)
- {
- uschar *mime_body,*reason_end;
+ if (subject.length==-1)
+ {
+ expand_header(&subject,&str_subject);
+ while (subject.length>=4 && Ustrncmp(subject.character,"Re: ",4)==0)
+ {
+ subject.character+=4;
+ subject.length-=4;
+ }
+ capacity=6;
+ start=6;
+ subject.character=string_cat(US"Auto: ",&capacity,&start,subject.character,subject.length);
+ subject.length=start;
+ }
+
+ /* add address to list of generated addresses */
+
+ addr = deliver_make_addr(string_sprintf(">%.256s", sender_address), FALSE);
+ setflag(addr, af_pfr);
+ setflag(addr, af_ignore_error);
+ addr->next = *generated;
+ *generated = addr;
+ addr->reply = store_get(sizeof(reply_item));
+ memset(addr->reply,0,sizeof(reply_item)); /* XXX */
+ addr->reply->to = string_copy(sender_address);
+ addr->reply->from = expand_string(US"$local_part@$domain");
+ /* Allocation is larger than neccessary, but enough even for split MIME words */
+ buffer_capacity=16+4*subject.length;
+ buffer=store_get(buffer_capacity);
+ addr->reply->subject=parse_quote_2047(subject.character, subject.length, US"utf-8", buffer, buffer_capacity);
+ addr->reply->oncelog=once;
+ addr->reply->once_repeat=days*86400;
+
+ /* build body and MIME headers */
+
+ if (reason_is_mime)
+ {
+ uschar *mime_body,*reason_end;
#ifdef RFC_EOL
- static const uschar nlnl[]="\r\n\r\n";
+ static const uschar nlnl[]="\r\n\r\n";
#else
- static const uschar nlnl[]="\n\n";
+ static const uschar nlnl[]="\n\n";
#endif

- for
- (
- mime_body=reason.character,reason_end=reason.character+reason.length;
- mime_body<(reason_end-sizeof(nlnl)-1) && memcmp(mime_body,nlnl,sizeof(nlnl)-1);
- ++mime_body
- );
- capacity = 0;
- start = 0;
- addr->reply->headers = string_cat(NULL,&capacity,&start,reason.character,mime_body-reason.character);
- addr->reply->headers[start] = '\0';
- capacity = 0;
- start = 0;
- if (mime_body+(sizeof(nlnl)-1)<reason_end) mime_body+=sizeof(nlnl)-1;
- else mime_body=reason_end-1;
- addr->reply->text = string_cat(NULL,&capacity,&start,mime_body,reason_end-mime_body);
- addr->reply->text[start] = '\0';
- }
- else
- {
- struct String qp;
+ for
+ (
+ mime_body=reason.character,reason_end=reason.character+reason.length;
+ mime_body<(reason_end-sizeof(nlnl)-1) && memcmp(mime_body,nlnl,sizeof(nlnl)-1);
+ ++mime_body
+ );
+ capacity = 0;
+ start = 0;
+ addr->reply->headers = string_cat(NULL,&capacity,&start,reason.character,mime_body-reason.character);
+ addr->reply->headers[start] = '\0';
+ capacity = 0;
+ start = 0;
+ if (mime_body+(sizeof(nlnl)-1)<reason_end) mime_body+=sizeof(nlnl)-1;
+ else mime_body=reason_end-1;
+ addr->reply->text = string_cat(NULL,&capacity,&start,mime_body,reason_end-mime_body);
+ addr->reply->text[start] = '\0';
+ }
+ else
+ {
+ struct String qp;

- capacity = 0;
- start = reason.length;
- addr->reply->headers = US"MIME-Version: 1.0\n"
- "Content-Type: text/plain;\n"
- "\tcharset=\"utf-8\"\n"
- "Content-Transfer-Encoding: quoted-printable";
- addr->reply->text = quoted_printable_encode(&reason,&qp)->character;
+ capacity = 0;
+ start = reason.length;
+ addr->reply->headers = US"MIME-Version: 1.0\n"
+ "Content-Type: text/plain;\n"
+ "\tcharset=\"utf-8\"\n"
+ "Content-Transfer-Encoding: quoted-printable";
+ addr->reply->text = quoted_printable_encode(&reason,&qp)->character;
+ }
}
}
- }
+ else if (filter_test != FTEST_NONE)
+ {
+ debug_printf("Sieve: mail was not personal, vacation would ignore it\n");
+ }
+ }
}
#endif
else break;
@@ -2727,7 +2739,7 @@
#ifdef VACATION
else if (eq_asciicase(check,&str_vacation,0))
{
- if (filter->vacation_directory == NULL)
+ if (filter_test == FTEST_NONE && filter->vacation_directory == NULL)
{
filter->errmsg=CUS "vacation disabled";
return -1;
@@ -2767,6 +2779,8 @@
options controls whether various special things are allowed, and requests
special actions (not currently used)
sieve_vacation_directory where to store vacation "once" files
+ useraddress string expression for :user part of address
+ subaddress string expression for :subaddress part of address
generated where to hang newly-generated addresses
error where to pass back an error text

@@ -2780,7 +2794,7 @@

int
sieve_interpret(uschar *filter, int options, uschar *vacation_directory,
- address_item **generated, uschar **error)
+ uschar *useraddress, uschar *subaddress, address_item **generated, uschar **error)
{
struct Sieve sieve;
int r;
@@ -2806,6 +2820,9 @@
}
}

+sieve.useraddress = useraddress == NULL ? CUS "$local_part_prefix$local_part$local_part_suffix" : useraddress;
+sieve.subaddress = subaddress;
+
#ifdef COMPILE_SYNTAX_CHECKER
if (parse_start(&sieve,0,generated)==1)
#else
--- src/functions.h.orig 2005-03-17 11:13:08.000000000 +0100
+++ src/functions.h 2005-03-17 11:14:21.000000000 +0100
@@ -179,7 +179,7 @@
#ifdef WITH_CONTENT_SCAN
extern int recv_line(int, uschar *, int);
#endif
-extern int rda_interpret(redirect_block *, int, uschar *, uschar *, ugid_block *,
+extern int rda_interpret(redirect_block *, int, uschar *, uschar *, uschar *, uschar *, ugid_block *,
address_item **, uschar **, error_block **, int *, uschar *);
extern int rda_is_filter(const uschar *);
extern BOOL readconf_depends(driver_instance *, uschar *);
@@ -242,8 +242,8 @@
extern void sha1_end(sha1 *, const uschar *, int, uschar *);
extern void sha1_mid(sha1 *, const uschar *);
extern void sha1_start(sha1 *);
-extern int sieve_interpret(uschar *, int, uschar *, address_item **,
- uschar **);
+extern int sieve_interpret(uschar *, int, uschar *, uschar *, uschar *,
+ address_item **, uschar **);
extern void sigalrm_handler(int);
extern void smtp_closedown(uschar *);
extern int smtp_connect(host_item *, int, int, uschar *, int, BOOL);
--- src/routers/queryprogram.c.orig 2005-03-17 11:17:25.000000000 +0100
+++ src/routers/queryprogram.c 2005-03-17 11:16:53.000000000 +0100
@@ -356,6 +356,8 @@
RDO_REWRITE, /* rewrite generated addresses */
NULL, /* :include: directory not relevant */
NULL, /* sieve vacation directory not relevant */
+ NULL, /* sieve user address not relevant */
+ NULL, /* sieve subaddress not relevant */
&ugid, /* uid/gid (but not set) */
&generated, /* where to hang the results */
&(addr->message), /* where to put messages */
--- src/routers/redirect.h.orig 2005-03-17 11:24:03.000000000 +0100
+++ src/routers/redirect.h 2005-03-17 11:24:36.000000000 +0100
@@ -25,6 +25,8 @@
uschar *include_directory;
uschar *pipe_transport_name;
uschar *reply_transport_name;
+ uschar *sieve_subaddress;
+ uschar *sieve_useraddress;
uschar *sieve_vacation_directory;
uschar *syntax_errors_text;
uschar *syntax_errors_to;
--- src/routers/redirect.c.orig 2005-03-17 11:20:49.000000000 +0100
+++ src/routers/redirect.c 2005-03-17 12:12:59.000000000 +0100
@@ -97,6 +97,10 @@
(void *)offsetof(redirect_router_options_block, reply_transport_name) },
{ "rewrite", opt_bit | (RDON_REWRITE << 16),
(void *)offsetof(redirect_router_options_block, bit_options) },
+ { "sieve_subaddress", opt_stringptr,
+ (void *)offsetof(redirect_router_options_block, sieve_subaddress) },
+ { "sieve_useraddress", opt_stringptr,
+ (void *)offsetof(redirect_router_options_block, sieve_useraddress) },
{ "sieve_vacation_directory", opt_stringptr,
(void *)offsetof(redirect_router_options_block, sieve_vacation_directory) },
{ "skip_syntax_errors", opt_bool,
@@ -138,6 +142,8 @@
NULL, /* include_directory */
NULL, /* pipe_transport_name */
NULL, /* reply_transport_name */
+ NULL, /* sieve_subaddress */
+ NULL, /* sieve_useraddress */
NULL, /* sieve_vacation_directory */
NULL, /* syntax_errors_text */
NULL, /* syntax_errors_to */
@@ -607,7 +613,7 @@
}

frc = rda_interpret(&redirect, options, ob->include_directory,
- ob->sieve_vacation_directory, &ugid, &generated, &(addr->message),
+ ob->sieve_vacation_directory, ob->sieve_useraddress, ob->sieve_subaddress, &ugid, &generated, &(addr->message),
ob->skip_syntax_errors? &eblock : NULL, &filtertype,
string_sprintf("%s router (recipient is %s)", rblock->name, addr->address));

--- src/deliver.c.orig 2005-03-17 11:26:08.000000000 +0100
+++ src/deliver.c 2005-03-17 11:26:34.000000000 +0100
@@ -4639,6 +4639,8 @@
RDO_REWRITE,
NULL, /* No :include: restriction (not used in filter) */
NULL, /* No sieve vacation directory (not sieve!) */
+ NULL, /* No sieve subaddress (not sieve!) */
+ NULL, /* No sieve useraddress (not sieve!) */
&ugid, /* uid/gid data */
&addr_new, /* Where to hang generated addresses */
&filter_message, /* Where to put error message */
--- src/filtertest.c.orig 2005-03-17 11:27:23.000000000 +0100
+++ src/filtertest.c 2005-03-17 11:28:12.000000000 +0100
@@ -271,7 +271,7 @@
else
{
yield = (filter_type == FILTER_SIEVE)?
- sieve_interpret(filebuf, RDO_REWRITE, NULL, &generated, &error)
+ sieve_interpret(filebuf, RDO_REWRITE, NULL, NULL, NULL, &generated, &error)
:
filter_interpret(filebuf, RDO_REWRITE, &generated, &error);
}
Re: Saving the variable part of local part suffixes [ In reply to ]
On Thu, 17 Mar 2005, Michael Haardt wrote:
>
> In fact, two new router options. I am not sure if this is interesting
> to Exim filters, because Exim filters could contain the string expression
> right away, so I did not add new variables. Opinions?

It's probably a good idea to add the variables so that people writing
Exim filters are insulated from the details of the site's subaddress
configuration, in the same way that Sieve users are.

> RFC 3598 allows to check other addresses than the envelope "to" address.
> There is a pretty good chance to get wrong results by applying the
> encoding rules for the currently processed envelope "to" address to other
> addresses. If processing other addresses, this implementation always
> uses the local part for :user and any test concerning :detail will be false.

This came up recently on the Sieve IETF working group list. I think your
approach is slightly better than their suggestion of sweeping the problem
under the carpet.

Tony.
--
<fanf@exim.org> <dot@dotat.at> http://dotat.at/ ${sg{\N${sg{\
N\}{([^N]*)(.)(.)(.*)}{\$1\$3\$2\$1\$3\n\$2\$3\$4\$3\n\$3\$2\$4}}\
\N}{([^N]*)(.)(.)(.*)}{\$1\$3\$2\$1\$3\n\$2\$3\$4\$3\n\$3\$2\$4}}
Re: Saving the variable part of local part suffixes [ In reply to ]
On Fri, Mar 18, 2005 at 12:57:07PM +0000, Tony Finch wrote:
> On Thu, 17 Mar 2005, Michael Haardt wrote:
> >
> > In fact, two new router options. I am not sure if this is interesting
> > to Exim filters, because Exim filters could contain the string expression
> > right away, so I did not add new variables. Opinions?
>
> It's probably a good idea to add the variables so that people writing
> Exim filters are insulated from the details of the site's subaddress
> configuration, in the same way that Sieve users are.

If the variables work in the filter, people will expect them to work in
transports, too, which requires expanding them when the router runs
and adding the results to the address_item.

Philip: Which approach do you prefer?

> > RFC 3598 allows to check other addresses than the envelope "to" address.
> > There is a pretty good chance to get wrong results by applying the
> > encoding rules for the currently processed envelope "to" address to other
> > addresses. If processing other addresses, this implementation always
> > uses the local part for :user and any test concerning :detail will be false.
>
> This came up recently on the Sieve IETF working group list. I think your
> approach is slightly better than their suggestion of sweeping the problem
> under the carpet.

Guess who brought it up there. ;-) Either it's just me, or the Exim
Sieve implementation is the first clean room implementation and that's
why I have so many problems with those RFCs.

Michael
Re: Saving the variable part of local part suffixes [ In reply to ]
On Fri, 18 Mar 2005, Michael Haardt wrote:

> If the variables work in the filter, people will expect them to work in
> transports, too, which requires expanding them when the router runs
> and adding the results to the address_item.
>
> Philip: Which approach do you prefer?

Sorry, I have not had time to think about this[*]. Could it be done for
Sieve first, and then variables added later if that seems like a good
idea?

-----------
[*] Until I finish work on documentation conversion (which is taking a
*lot* of time), I'm not working much on the code. I'm also trying to
keep the next release of PCRE moving (slowly) and working on Exim
teaching/presentation materials. So I'm afraid for the next few weeks
I'll be giving that response quite frequently (and after that I'm away
again).

--
Philip Hazel University of Cambridge Computing Service,
ph10@cus.cam.ac.uk Cambridge, England. Phone: +44 1223 334714.
Get the Exim 4 book: http://www.uit.co.uk/exim-book
Re: Saving the variable part of local part suffixes [ In reply to ]
> > If the variables work in the filter, people will expect them to work in
> > transports, too, which requires expanding them when the router runs
> > and adding the results to the address_item.
> >
> > Philip: Which approach do you prefer?
>
> Sorry, I have not had time to think about this[*]. Could it be done for
> Sieve first, and then variables added later if that seems like a good
> idea?

Yes, no problem. I will work on a final patch then that omits variables
for now. Adding them later will not influence the user-visible part.

Michael