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.