This follows on from my previous email, where I presented a method of
enabling sieving on mail delivered directly to shared/public folders.

While that does all the I need it to do, my implementation only allowed
a single active script for all public folders. This is a serious
limitation if you want to allow different people to maintain different
policies (i.e. scripts) for different folders, or sets of folders in the
hierarchy.

The following implementation addresses this concern.

In addition, the problems of a confusing name space (i.e. where are
these scripts stored) together with administering them (i.e. how can I
get to these scripts) were raised. Again, I've attempted to address
this.

1. Namespace issues

The imap server presents a unified hierarchy of folders and subfolders.
I'll call this the IMAP namespace. Typically, the "." is used as a
delimiter, although this can be overridden.

Each folder and items in the folder are mapped through to directories
and files on the server. This mapping is invisible to users of the imap
server. The system administrator creates this mapping by specifying
partitions - folder storage is assigned to a partition. In addition, a
simple hash mechanism can be used in order to add an additional
directory level to the system storage for performance reasons.
Consequently the mapping of the the IMAP namespace to the system name
space is non trivial. The key point to note is that it is hidden from
the user of the imap server. In general terms. folder "user.ian" might
map to <partition>/[<hash>]/user/ian. In a system with a single default
partition set to "/var/spool/imap", with hashing enabled, the folder
would map to "/var/spool/imap/i/user/ian".

2. What is being sieved.

Messages are sieved on delivery. The sieve specification doesn't
explicitly say how a given sieve script should apply to a particular
message. Currently, this is defined by the implementation is Cyrus. In
this case, messages delivered to "user.<someuser>" are filtered with a
script located using a _different_ namespace mapping to the one used for
folder storage. In particular, for sieving purposes, the folder
"user.<someuser>.[<folders>] will map to the same internal name space as
the folder "user.<someuser>". Additionally, there is no valid mapping
for any other folder. i.e. "<anothertoplevelfolder>.[<folders>] will
never match against a sieve script.

[OK, this is a somewhat baroque way of saying that currently, you can't
sieve public folders, and a user can have only one script - but I'm
trying to show that sieving functionality can be extended without
altering any fundamental concepts].

3. A single name space for folder storage and sieve scripts

If we use the same name space mapping rules that we have for folders to
scripts, then we can solve the problem.

So a message being delivered to "user.fred" should be sieved with a
script associated with that particular name. Then a message being
delivered to a folder public.interesting.messages should be filtered
with a script associated with that folder name.

4. How should the mapping be performed

Essentially, the same way that the mapping for folders is performed.
I.e. a given imap namespace (folder) will map to a unique/distinct
system directory. We want the same to hold true for scripts.A logical
thing to do would be to use exactly the same mapping, and store the
script for the folder with the rest of the files. However, the current
implementation doesn't do that, and we don't want to break it.. so:

a folder "a.b.c" maps to <partition>/[hash]/a/b/c, so if we use
"sievedir" we can simply do: "<sievedir>/[hash]/a/b/c for ths folder.

In this case, wether or not the hash function is used is determined by
"hashimapspool". The name space (apart from the root) will be the same.
Of course, if you have a single "partition_default:" mapping to
/var/spool/imap, and make sievedir map to /var/spool/imap then you will
have exactly the same imap -> physical mapping.

5. Compatibility issues.

The suggested implementation should be compatible with the existing one.
In this case, we would want the folder [user.ian.my.sub.folder] to map
to the script for [user.ian] - which it does now. This can be achieved
by saying, if there is no script for this pariticular namespace, then
try the script for the mapping of the folders parent. Keep doing this
until you find the script. So if the only active script was associated
with "user.ian", then all subfolders would use this script.

This is nice because it is both compatible with the existing
implementation, and also allows a single script to be used for a
collection of similar folders. I.e. a script has a scope of its
specified folder together with all its children. Or you can say that
subfolders inherit the script of the parent.

6. Script Execution.

This isn't changed in anyway. "Deliver" is simply determining what
script to run. In security terms, scripts run with the rights of the
user with which they are associated. This is again implicitly defined as
folders do not have the concept of an owner. You simply own folders that
are located in your INBOX. For public folders, the script is run with
the rights of the special/pseudo user "anyone". [Perhaps this should be
configurable - there may be some cases that I am unable to think of at
the moment where this wouldn't be wanted].

7. Script Management

Who can manage/install a script? The obvious thing to do seems to be to
use the "a" administrator access folder setting. This should be set on
your own folders, so again, perfect backwards compatibility is
preserved.

"timsieved" is extended with an additional command "folder" (a bit like
the UNIX cd command). When you authenticate your own inbox is your
current folder - so again, behaviour is before.

The folder command takes an IMAP folder specification as its argument.
Thus the the imap server still hides the physical mapping from the user.

for example "folder public.interesting.messages"

would set the context to that folder. A check is done so that this
command will only succeed if 1) the folder already exists and 2) the
authenticated user has the "a" access rights. "folder" with no
parameters should set the current folder back to the inbox. 

If the directory holding the script does not exist, then it will be
silently created (this is preserving the existing behaviour) - folders
are created using cyradm in the usual way. If a folder exists then a
script may be set for it.

Otherwise the behaviour of timsieved is unchanged (i.e. ls, get, put,
activate etc. all still apply).

8. The implementation

I've coded this against CVS. As I write I've not implemented the access
rights checking part (should be trivial). I've also not thought about
what to do if "sievehomedir" is being used - probably just keep the
existing behaviour as without timsieved to install the scripts, there
isn't a lot of point in having the facility.

Otherwise, it is pretty complete. I should point that the underlying
name space is different - so existing scripts will be in the wrong
location. This is an upgrade/conversion issue which I don't want to
worry about at the moment...

8. Summary

I think this is a good solution because:

- No new concepts are introduced, it is rather a clarification of
existing ones
- Backwards compatibility is preserved
- You get some nice cool features - sieving on public folders, having
different scripts for different folders - including your own sub
folders, different people can maintain different folders
- Shouldn't have any particular performance implications.


10. I'll send the source along in a little while.... as it is tea time
now... Should I be sending code to this list - or is there some other
address?


Regards,


Ian.



Reply via email to