]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blame - src/patches/cyrus-imapd-2.2.12-autocreate-0.9.4.diff
Merge branch 'ppp-update' into beyond-next
[people/teissler/ipfire-2.x.git] / src / patches / cyrus-imapd-2.2.12-autocreate-0.9.4.diff
CommitLineData
b40388bb
MT
1diff -Naur cyrus-imapd-2.2.12/README.autocreate cyrus-imapd-2.2.12.autocreate2/README.autocreate
2--- cyrus-imapd-2.2.12/README.autocreate 1970-01-01 02:00:00.000000000 +0200
3+++ cyrus-imapd-2.2.12.autocreate2/README.autocreate 2005-10-19 14:48:57.930991000 +0300
4@@ -0,0 +1,181 @@
5+Cyrus IMAP autocreate Inbox patch
6+----------------------------------
7+
8+NOTE : This patch has been created at the University of Athens. For more info, as well
9+as more patches on Cyrus IMAPD server, please visit http://email.uoa.gr
10+
11+The design of Cyrus IMAP server does not predict the automatic creation of users'
12+INBOX folders. The creation of a user's INBOX is considered to be an external task,
13+that has to be completed as part of the user e-mail account creation procedure.
14+Hence, to create a new e-mail account the site administrator has to
15+a) Include the new account in the user database for the authentication procedure
16+ (e.g. sasldb, shadow, mysql, ldap).
17+b) Create the corresponding INBOX folder.
18+
19+Alternatively, the user, if succesfully authenticated, may create his own INBOX folder,
20+as long as the configuration of the site allows it (see "autocreatequota" in imapd.conf).
21+Unlike what uncareful readers may think, enabling the "autocreatequota" option, doesn't
22+lead to the automatic INBOX folder creation by Cyrus IMAP server.
23+In fact, "autocreate" means that the IMAP clients are allowed to automatically create
24+the user INBOX.
25+
26+This patch adds the functionality of automatic creation of the users' INBOX folders into
27+the Cyrus IMAP server. It is implemented as two features, namely the "create on login"
28+and "create on post".
29+
30+
31+
32+Create on login
33+===============
34+This feauture provides automatic creation of a user's INBOX folder when all of the
35+following requirements are met:
36+
37+i) The user has succesfully passed the authentication procedure.
38+
39+ii) The user's authorization ID (typically the same as the user's
40+authentication ID) doesn't belong to the imap_admins or admins
41+accounts (see imapd.conf).
42+
43+iii) The "autocreatequota" option in the imap configuration file
44+has been set to a non zero value.
45+
46+iv) The corresponding to the user's authorizationID INBOX folder
47+does not exist.
48+
49+The user's first login is the most typical case when all four requirements are met.
50+Note that if the authenticatedID is allowed to proxy to another account for which
51+all of the above requirements are met, the corresponding INBOX folder for that account
52+will be created.
53+
54+
55+
56+Create on post
57+==============
58+This feauture provides automatic creation of a user's INBOX folder when all of the
59+following requirements are met.
60+
61+i) An e-mail message addressed to the user has been received.
62+
63+ii) The recipient is not any of the imap_admins or admins accounts.
64+Note that passing e-mails to admins or imap_admins accounts from
65+the MTA to LMTP should be avoided in any case.
66+
67+iii) The recipient's INBOX does not exist.
68+
69+iv) The "autocreatequota" option in the imap configuration file
70+has been set to a non zero value.
71+
72+v) The "createonpost" option in the imap configuration file
73+has been switched on.
74+
75+
76+Besides the automatic creation of INBOX folder, additional functionalities are
77+provided:
78+
79+A) Automatic creation of INBOX subfolders controlled by "autocreateinboxfolders"
80+configuration option. eg
81+
82+autocreateinboxfolders: sent|drafts|spam|templates
83+
84+B) Automatic subscription of INBOX subfolders controlled by "autosubscribeinboxfolders"
85+configuration option. eg
86+
87+autosubscribeinboxfolders: sent|spam
88+
89+Obviously, only subscription to subfolders included in the "autocreateinboxfolder"
90+list is meaningfull.
91+
92+C) Automatic subscription to shared folders (bulletin boards). The user gets
93+automatically subscribed to the shared folders declared in the "autosubscribesharedfolders"
94+configuration option in imapd.conf.
95+eg autosubscribesharedfolders: public_folder | public_folder.subfolder
96+
97+In order the above action to succeed, the shared folder has to pre-exist the INBOX creation
98+and the user must have the apropriate permissions in order to be able to subscribe to the
99+shared folder.
100+
101+* A new config option has been added. 'autosubscribe_all_sharedfolders' is a yes/no
102+option. When set to yes, the user is automatically subscribed to all shared folders one
103+has permission to subscribe to. Please, note that when this option is set to yes, then
104+'autosubscribesharedfolders' option is overriden.
105+
106+D) Automatic creation of a predefined default sieve script.
107+
108+This is very useful when a default sieve script is used for every user. Usually, a
109+default anti-spam script may me be written in a file and copied to each user
110+sieve scripts upon the INBOX creation. The imapd.conf options that have been added
111+are 'autocreate_sieve_script', 'autocreate_sieve_compiledscript' and
112+'generate_compiled_sieve_script'.
113+
114+autocreate_sieve_script configuration option refers to the full path of the file
115+that contains the sieve script. The default value is null and if no file is defined,
116+then no default script is created upon INBOX creation. (The feature is disabled)
117+eg autocreate_sieve_script: /etc/default_sieve_script
118+
119+autocreate_sieve_compiledscript configuration option refers to the full path of the
120+file that contains the bytecode compiled sieve script. If this filename is defined
121+in imapd.conf and the file exists, then it is automatically copied in the user's sieve
122+directory. If it is not defined, then a bytecode sieve script gets on the fly compiled
123+by the daemon.
124+eg autocreate_sieve_compiledscript: /etc/default_sieve_script.bc
125+
126+generate_compiled_sieve_script is a boolean option that triggers the compilation of the
127+source sieve script to bytecode sieve script. The file that the bytecode script will
128+be saved is pointed by autocreate_sieve_compiledscript.
129+
130+Ways of compiling a sieve script :
131+1. Compile a sieve script using the standard sievec utility, distributed by CMU
132+2. Compile a sieve script using the compile_sieve utility, released by UoA. This
133+ tool is almost identical to the sievec utility, with the difference that it
134+ reads the input and output file from autocreate_sieve_script and
135+ autocreate_sieve_compiledscript options in imapd.conf
136+3. Let cyrus create a compiled sieve script using a source script. Cyrus can be
137+ instructed to save the compiled script any time a compiled script does not exist.
138+
139+NOTES :
140+1. In order this functionality to work, the following requirements must have been met:
141+ - 'sieveusehomedir' option must be 'no' in the configuration (default).
142+ - 'sievedir' option must have a valid value.
143+2. Currently, this patch checks the validity of the source script while generating a
144+ bytecode compiled script, but not the validity of the bytecode sieve script file.
145+ The administrator should make sure that the provided files contain a valid sieve
146+ script as well as the compiled script is updated every time the source script changes.
147+
148+
149+
150+Issues to be considered
151+=======================
152+
153+I) In order to use the create on post feauture one should be absolutely sure that:
154+a) The MTA checks the validity of the e-mail recipient before sending the e-mail to
155+LMTP. This is an RFC821 requirement. This usually expands to "the mta should be
156+able to use the account database as user mailbox database".
157+b) Only authorized accounts/services can talk to LMTP.
158+
159+II) Especially in the case of imap logins, the current patch implementation checks
160+for the INBOX folder existence upon login, causing an extra mailbox lookup in most
161+of the cases.
162+A better approach would be to chase the "IMAP_MAILBOX_NONEXISTENT" error code and
163+check if the error is associated with an INBOX folder. However, this would mess up
164+Cyrus code. The way it was implemented may not have been the most performance
165+optimized, but it produces a much cleaner and simple patch.
166+
167+
168+
169+Virtual Domains Support
170+=======================
171+
172+Virtual domains are supported by all versions of the patch for cyrus-imapd-2.2.1-BETA and
173+later. However, it is not possible to declare different INBOX subfolders to be created or
174+shared folders to be subscribed to for every domain.
175+
176+
177+
178+Things to be done
179+=================
180+
181+1. Support MURDER architecture.
182+
183+
184+For more information and updates please visit http://email.uoa.gr/autocreate
185+
186diff -Naur cyrus-imapd-2.2.12/imap/Makefile.in cyrus-imapd-2.2.12.autocreate2/imap/Makefile.in
187--- cyrus-imapd-2.2.12/imap/Makefile.in 2004-05-28 21:03:02.000000000 +0300
188+++ cyrus-imapd-2.2.12.autocreate2/imap/Makefile.in 2005-10-19 14:48:57.935240000 +0300
189@@ -104,7 +104,7 @@
190 convert_code.o duplicate.o saslclient.o saslserver.o signals.o \
191 annotate.o search_engines.o squat.o squat_internal.o mbdump.o \
192 imapparse.o telemetry.o user.o notify.o protocol.o quota_db.o \
193- $(SEEN) $(IDLE)
194+ autosieve.o $(SEEN) $(IDLE)
195
196 IMAPDOBJS=pushstats.o backend.o imapd.o index.o tls.o version.o
197
198@@ -122,7 +122,7 @@
199 fud smmapd reconstruct quota mbpath ipurge \
200 cyrdump chk_cyrus cvt_cyrusdb deliver ctl_mboxlist \
201 ctl_deliver ctl_cyrusdb squatter mbexamine cyr_expire arbitron \
202- @IMAP_PROGS@
203+ compile_sieve @IMAP_PROGS@
204
205 BUILTSOURCES = imap_err.c imap_err.h pushstats.c pushstats.h \
206 lmtpstats.c lmtpstats.h xversion.h mupdate_err.c mupdate_err.h \
207@@ -188,7 +188,7 @@
208 ### Services
209 idled: idled.o mutex_fake.o libimap.a $(DEPLIBS)
210 $(CC) $(LDFLAGS) -o idled \
211- idled.o mutex_fake.o libimap.a $(DEPLIBS) $(LIBS)
212+ idled.o mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
213
214 lmtpd: lmtpd.o $(LMTPOBJS) $(SIEVE_OBJS) mutex_fake.o libimap.a $(SIEVE_LIBS) \
215 $(DEPLIBS) $(SERVICE)
216@@ -214,10 +214,10 @@
217 $(SERVICE) lmtpproxyd.o backend.o $(LMTPOBJS) mutex_fake.o \
218 libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
219
220-imapd: xversion $(IMAPDOBJS) mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
221+imapd: xversion $(IMAPDOBJS) mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(SERVICE)
222 $(CC) $(LDFLAGS) -o imapd \
223 $(SERVICE) $(IMAPDOBJS) mutex_fake.o \
224- libimap.a $(DEPLIBS) $(LIBS) $(LIB_WRAP)
225+ libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
226
227 imapd.pure: $(IMAPDOBJS) mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
228 $(PURIFY) $(PUREOPT) $(CC) $(LDFLAGS) -o imapd.pure \
229@@ -232,7 +232,7 @@
230 proxyd: $(PROXYDOBJS) mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
231 $(CC) $(LDFLAGS) -o proxyd \
232 $(SERVICE) $(PROXYDOBJS) mutex_fake.o libimap.a \
233- $(DEPLIBS) $(LIBS) $(LIB_WRAP)
234+ $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
235
236 proxyd.pure: $(PROXYDOBJS) mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
237 $(PURIFY) $(PUREOPT) $(CC) $(LDFLAGS) -o proxyd.pure \
238@@ -244,7 +244,7 @@
239 $(CC) $(LDFLAGS) -o mupdate \
240 $(SERVICETHREAD) mupdate.o mupdate-slave.o mupdate-client.o \
241 mutex_pthread.o tls.o libimap.a \
242- $(DEPLIBS) $(LIBS) $(LIB_WRAP) -lpthread
243+ $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP) -lpthread
244
245 mupdate.pure: mupdate.o mupdate-slave.o mupdate-client.o mutex_pthread.o \
246 libimap.a $(DEPLIBS)
247@@ -252,92 +252,96 @@
248 $(SERVICETHREAD) mupdate.o mupdate-slave.o mupdate-client.o \
249 mutex_pthread.o libimap.a $(DEPLIBS) $(LIBS) $(LIB_WRAP) -lpthread
250
251-pop3d: pop3d.o backend.o tls.o mutex_fake.o libimap.a $(DEPLIBS) $(SERVICE)
252+pop3d: pop3d.o backend.o tls.o mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(SERVICE)
253 $(CC) $(LDFLAGS) -o pop3d pop3d.o backend.o tls.o $(SERVICE) \
254- mutex_fake.o libimap.a $(DEPLIBS) $(LIBS) $(LIB_WRAP)
255+ mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
256
257 nntpd: nntpd.o backend.o index.o smtpclient.o spool.o tls.o \
258 mutex_fake.o nntp_err.o libimap.a $(DEPLIBS) $(SERVICE)
259 $(CC) $(LDFLAGS) -o nntpd nntpd.o backend.o index.o spool.o \
260 smtpclient.o tls.o $(SERVICE) mutex_fake.o nntp_err.o \
261- libimap.a $(DEPLIBS) $(LIBS) $(LIB_WRAP)
262+ libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
263
264-fud: fud.o libimap.a mutex_fake.o $(DEPLIBS) $(SERVICE)
265+fud: fud.o libimap.a mutex_fake.o $(SIEVE_LIBS) $(DEPLIBS) $(SERVICE)
266 $(CC) $(LDFLAGS) -o fud $(SERVICE) fud.o mutex_fake.o libimap.a \
267- $(DEPLIBS) $(LIBS) $(LIB_WRAP)
268+ $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
269
270-smmapd: smmapd.o libimap.a mutex_fake.o $(DEPLIBS) $(SERVICE)
271+smmapd: smmapd.o libimap.a mutex_fake.o $(SIEVE_LIBS) $(DEPLIBS) $(SERVICE)
272 $(CC) $(LDFLAGS) -o smmapd $(SERVICE) smmapd.o mutex_fake.o libimap.a \
273- $(DEPLIBS) $(LIBS) $(LIB_WRAP)
274+ $(SIEVE_LIBS) $(DEPLIBS) $(LIBS) $(LIB_WRAP)
275
276 ### Command Line Utilities
277-arbitron: arbitron.o $(CLIOBJS) libimap.a $(DEPLIBS)
278+arbitron: arbitron.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
279 $(CC) $(LDFLAGS) -o arbitron arbitron.o $(CLIOBJS) \
280- libimap.a $(DEPLIBS) $(LIBS)
281+ libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
282+
283+compile_sieve: compile_sieve.o libimap.a $(SIEVE_LIBS) $(DEPLIBS)
284+ $(CC) $(LDFLAGS) -o compile_sieve compile_sieve.o $(CLIOBJS) \
285+ libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
286
287-cvt_cyrusdb: cvt_cyrusdb.o mutex_fake.o libimap.a $(DEPLIBS)
288+cvt_cyrusdb: cvt_cyrusdb.o mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS)
289 $(CC) $(LDFLAGS) -o cvt_cyrusdb cvt_cyrusdb.o $(CLIOBJS) \
290- libimap.a $(DEPLIBS) $(LIBS)
291+ libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
292
293-chk_cyrus: chk_cyrus.o mutex_fake.o libimap.a $(DEPLIBS)
294+chk_cyrus: chk_cyrus.o mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS)
295 $(CC) $(LDFLAGS) -o chk_cyrus chk_cyrus.o $(CLIOBJS) \
296- libimap.a $(DEPLIBS) $(LIBS)
297+ libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
298
299-deliver: deliver.o backend.o $(LMTPOBJS) mutex_fake.o libimap.a $(DEPLIBS)
300+deliver: deliver.o backend.o $(LMTPOBJS) mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS)
301 $(CC) $(LDFLAGS) -o deliver deliver.o backend.o $(LMTPOBJS) \
302- mutex_fake.o libimap.a $(DEPLIBS) $(LIBS)
303+ mutex_fake.o libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
304
305-ctl_deliver: ctl_deliver.o $(CLIOBJS) libimap.a $(DEPLIBS)
306+ctl_deliver: ctl_deliver.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
307 $(CC) $(LDFLAGS) -o \
308- $@ ctl_deliver.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
309+ $@ ctl_deliver.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
310
311-ctl_mboxlist: ctl_mboxlist.o mupdate-client.o $(CLIOBJS) libimap.a $(DEPLIBS)
312+ctl_mboxlist: ctl_mboxlist.o mupdate-client.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
313 $(CC) $(LDFLAGS) -o $@ ctl_mboxlist.o mupdate-client.o $(CLIOBJS) \
314- libimap.a $(DEPLIBS) $(LIBS)
315+ libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
316
317-ctl_cyrusdb: ctl_cyrusdb.o $(CLIOBJS) libimap.a $(DEPLIBS)
318+ctl_cyrusdb: ctl_cyrusdb.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
319 $(CC) $(LDFLAGS) -o \
320- $@ ctl_cyrusdb.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
321+ $@ ctl_cyrusdb.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
322
323-cyr_expire: cyr_expire.o $(CLIOBJS) libimap.a $(DEPLIBS)
324+cyr_expire: cyr_expire.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
325 $(CC) $(LDFLAGS) -o $@ cyr_expire.o $(CLIOBJS) \
326- libimap.a $(DEPLIBS) $(LIBS)
327+ libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
328
329-fetchnews: fetchnews.o $(CLIOBJS) libimap.a $(DEPLIBS)
330+fetchnews: fetchnews.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
331 $(CC) $(LDFLAGS) -o \
332- $@ fetchnews.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
333+ $@ fetchnews.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
334
335-squatter: squatter.o index.o squat_build.o $(CLIOBJS) libimap.a $(DEPLIBS)
336+squatter: squatter.o index.o squat_build.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
337 $(CC) $(LDFLAGS) -o squatter squatter.o index.o squat_build.o \
338- $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
339+ $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
340
341-mbpath: mbpath.o $(CLIOBJS) libimap.a $(DEPLIBS)
342+mbpath: mbpath.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
343 $(CC) $(LDFLAGS) -o mbpath mbpath.o $(CLIOBJS) libimap.a \
344- $(DEPLIBS) $(LIBS)
345+ $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
346
347-ipurge: ipurge.o $(CLIOBJS) libimap.a $(DEPLIBS)
348+ipurge: ipurge.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
349 $(CC) $(LDFLAGS) -o ipurge ipurge.o $(CLIOBJS) \
350- libimap.a $(DEPLIBS) $(LIBS)
351+ libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
352
353-cyrdump: cyrdump.o index.o $(CLIOBJS) libimap.a $(DEPLIBS)
354+cyrdump: cyrdump.o index.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
355 $(CC) $(LDFLAGS) -o cyrdump cyrdump.o index.o $(CLIOBJS) \
356- libimap.a $(DEPLIBS) $(LIBS)
357+ libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
358
359-mbexamine: mbexamine.o $(CLIOBJS) libimap.a $(DEPLIBS)
360+mbexamine: mbexamine.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
361 $(CC) $(LDFLAGS) -o \
362- mbexamine mbexamine.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
363+ mbexamine mbexamine.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
364
365-reconstruct: reconstruct.o $(CLIOBJS) libimap.a $(DEPLIBS)
366+reconstruct: reconstruct.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
367 $(CC) $(LDFLAGS) -o \
368- reconstruct reconstruct.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
369+ reconstruct reconstruct.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
370
371-quota: quota.o $(CLIOBJS) libimap.a $(DEPLIBS)
372+quota: quota.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
373 $(CC) $(LDFLAGS) -o quota quota.o $(CLIOBJS) \
374- libimap.a $(DEPLIBS) $(LIBS)
375+ libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
376
377-tls_prune: tls_prune.o tls.o $(CLIOBJS) libimap.a $(DEPLIBS)
378+tls_prune: tls_prune.o tls.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS)
379 $(CC) $(LDFLAGS) -o \
380- $@ tls_prune.o tls.o $(CLIOBJS) libimap.a $(DEPLIBS) $(LIBS)
381+ $@ tls_prune.o tls.o $(CLIOBJS) libimap.a $(SIEVE_LIBS) $(DEPLIBS) $(LIBS)
382
383 ### Other Misc Targets
384
385diff -Naur cyrus-imapd-2.2.12/imap/autosieve.c cyrus-imapd-2.2.12.autocreate2/imap/autosieve.c
386--- cyrus-imapd-2.2.12/imap/autosieve.c 1970-01-01 02:00:00.000000000 +0200
387+++ cyrus-imapd-2.2.12.autocreate2/imap/autosieve.c 2005-10-19 14:48:57.940098000 +0300
388@@ -0,0 +1,587 @@
389+#include <stdio.h>
390+#include <stdlib.h>
391+#include <string.h>
392+
393+#ifdef HAVE_UNISTD_H
394+#include <unistd.h>
395+#endif
396+
397+#include <errno.h>
398+#include <sys/types.h>
399+#include <sys/stat.h>
400+#include <sys/uio.h>
401+#include <fcntl.h>
402+#include <ctype.h>
403+#include <time.h>
404+#include <syslog.h>
405+#include <com_err.h>
406+#include <config.h>
407+
408+#include "global.h"
409+#include "util.h"
410+#include "mailbox.h"
411+#include "imap_err.h"
412+#include "sieve_interface.h"
413+#include "script.h"
414+
415+#define TIMSIEVE_FAIL -1
416+#define TIMSIEVE_OK 0
417+#define MAX_FILENAME 1024
418+
419+static int get_script_name(char *sievename, size_t buflen, const char *filename);
420+static int get_script_dir(char *sieve_script_dir, size_t buflen, char *userid, const char *sieve_dir);
421+int autoadd_sieve(char *userid, const char *source_script);
422+
423+static void fatal(const char *s, int code);
424+static void foo(void);
425+static int sieve_notify(void *ac __attribute__((unused)),
426+ void *interp_context __attribute__((unused)),
427+ void *script_context __attribute__((unused)),
428+ void *message_context __attribute__((unused)),
429+ const char **errmsg __attribute__((unused)));
430+static int mysieve_error(int lineno, const char *msg,
431+ void *i __attribute__((unused)), void *s);
432+static int is_script_parsable(FILE *stream, char **errstr, sieve_script_t **ret);
433+
434+
435+sieve_vacation_t vacation2 = {
436+ 0, /* min response */
437+ 0, /* max response */
438+ (sieve_callback *) &foo, /* autorespond() */
439+ (sieve_callback *) &foo /* send_response() */
440+};
441+
442+
443+/*
444+ * Find the name of the sieve script
445+ * given the source script and compiled script names
446+ */
447+static int get_script_name(char *sievename, size_t buflen, const char *filename)
448+{
449+ char *p;
450+ int r;
451+
452+ p = strrchr(filename, '/');
453+ if (p == NULL)
454+ p = (char *) filename;
455+ else
456+ p++;
457+
458+ r = strlcpy(sievename, p, buflen) - buflen;
459+ return (r >= 0 || r == -buflen ? 1 : 0);
460+}
461+
462+
463+/*
464+ * Find the directory where the sieve scripts of the user
465+ * reside
466+ */
467+static int get_script_dir(char *sieve_script_dir, size_t buflen, char *userid, const char *sieve_dir)
468+{
469+ char *user = NULL, *domain = NULL;
470+
471+ /* Setup the user and the domain */
472+ if(config_virtdomains && (domain = strchr(userid, '@'))) {
473+ user = (char *) xmalloc((domain - userid +1) * sizeof(char));
474+ strlcpy(user, userid, domain - userid + 1);
475+ domain++;
476+ } else
477+ user = userid;
478+
479+ /* Find the dir path where the sieve scripts of the user will reside */
480+ if (config_virtdomains && domain) {
481+ if(snprintf(sieve_script_dir, buflen, "%s%s%c/%s/%c/%s/",
482+ sieve_dir, FNAME_DOMAINDIR, dir_hash_c(domain), domain, dir_hash_c(user), user) >= buflen) {
483+ free(user);
484+ return 1;
485+ }
486+ } else {
487+ if(snprintf(sieve_script_dir, buflen, "%s/%c/%s/",
488+ sieve_dir, dir_hash_c(user), user) >= buflen)
489+ return 1;
490+ }
491+
492+ /* Free the xmalloced user memory, reserved above */
493+ if(user != userid)
494+ free(user);
495+
496+ return 0;
497+}
498+
499+int autoadd_sieve(char *userid, const char *source_script)
500+{
501+ sieve_script_t *s = NULL;
502+ bytecode_info_t *bc = NULL;
503+ char *err = NULL;
504+ FILE *in_stream, *out_fp;
505+ int out_fd, in_fd, r, k;
506+ int do_compile = 0;
507+ const char *sieve_dir = NULL;
508+ const char *compiled_source_script = NULL;
509+ char sievename[MAX_FILENAME];
510+ char sieve_script_name[MAX_FILENAME];
511+ char sieve_script_dir[MAX_FILENAME];
512+ char sieve_bcscript_name[MAX_FILENAME];
513+ char sieve_default[MAX_FILENAME];
514+ char sieve_tmpname[MAX_FILENAME];
515+ char sieve_bctmpname[MAX_FILENAME];
516+ char sieve_bclink_name[MAX_FILENAME];
517+ char buf[4096];
518+ mode_t oldmask;
519+ struct stat statbuf;
520+
521+ /* We don't support using the homedirectory, like timsieved */
522+ if (config_getswitch(IMAPOPT_SIEVEUSEHOMEDIR)) {
523+ syslog(LOG_WARNING,"autocreate_sieve: autocreate_sieve does not work with sieveusehomedir option in imapd.conf");
524+ return 1;
525+ }
526+
527+ /* Check if sievedir is defined in imapd.conf */
528+ if(!(sieve_dir = config_getstring(IMAPOPT_SIEVEDIR))) {
529+ syslog(LOG_WARNING, "autocreate_sieve: sievedir option is not defined. Check imapd.conf");
530+ return 1;
531+ }
532+
533+ /* Check if autocreate_sieve_compiledscript is defined in imapd.conf */
534+ if(!(compiled_source_script = config_getstring(IMAPOPT_AUTOCREATE_SIEVE_COMPILEDSCRIPT))) {
535+ syslog(LOG_WARNING, "autocreate_sieve: autocreate_sieve_compiledscript option is not defined. Compiling it");
536+ do_compile = 1;
537+ }
538+
539+ if(get_script_dir(sieve_script_dir, sizeof(sieve_script_dir), userid, sieve_dir)) {
540+ syslog(LOG_WARNING, "autocreate_sieve: Cannot find sieve scripts directory");
541+ return 1;
542+ }
543+
544+ if (get_script_name(sievename, sizeof(sievename), source_script)) {
545+ syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve script %s", source_script);
546+ return 1;
547+ }
548+
549+ if(snprintf(sieve_tmpname, sizeof(sieve_tmpname), "%s%s.script.NEW",sieve_script_dir, sievename) >= sizeof(sieve_tmpname)) {
550+ syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_dir, sievename, userid);
551+ return 1;
552+ }
553+ if(snprintf(sieve_bctmpname, sizeof(sieve_bctmpname), "%s%s.bc.NEW",sieve_script_dir, sievename) >= sizeof(sieve_bctmpname)) {
554+ syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_dir, sievename, userid);
555+ return 1;
556+ }
557+ if(snprintf(sieve_script_name, sizeof(sieve_script_name), "%s%s.script",sieve_script_dir, sievename) >= sizeof(sieve_script_name)) {
558+ syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_dir, sievename, userid);
559+ return 1;
560+ }
561+ if(snprintf(sieve_bcscript_name, sizeof(sieve_bcscript_name), "%s%s.bc",sieve_script_dir, sievename) >= sizeof(sieve_bcscript_name)) {
562+ syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_dir, sievename, userid);
563+ return 1;
564+ }
565+ if(snprintf(sieve_default, sizeof(sieve_default), "%s%s",sieve_script_dir,"defaultbc") >= sizeof(sieve_default)) {
566+ syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_dir, sievename, userid);
567+ return 1;
568+ }
569+ if(snprintf(sieve_bclink_name, sizeof(sieve_bclink_name), "%s.bc", sievename) >= sizeof(sieve_bclink_name)) {
570+ syslog(LOG_WARNING, "autocreate_sieve: Invalid sieve path %s, %s, %s", sieve_dir, sievename, userid);
571+ return 1;
572+ }
573+
574+ /* Check if a default sieve filter alrady exists */
575+ if(!stat(sieve_default,&statbuf)) {
576+ syslog(LOG_WARNING,"autocreate_sieve: Default sieve script already exists");
577+ fclose(in_stream);
578+ return 1;
579+ }
580+
581+ /* Open the source script. if there is a problem with that exit */
582+ in_stream = fopen(source_script, "r");
583+ if(!in_stream) {
584+ syslog(LOG_WARNING,"autocreate_sieve: Unable to open sieve script %s. Check permissions",source_script);
585+ return 1;
586+ }
587+
588+
589+ /*
590+ * At this point we start the modifications of the filesystem
591+ */
592+
593+ /* Create the directory where the sieve scripts will reside */
594+ r = cyrus_mkdir(sieve_script_dir, 0755);
595+ if(r == -1) {
596+ /* If this fails we just leave */
597+ syslog(LOG_WARNING,"autocreate_sieve: Unable to create directory %s. Check permissions",sieve_script_name);
598+ return 1;
599+ }
600+
601+ /*
602+ * We open the file that will be used as the bc file. If this file exists, overwrite it
603+ * since something bad has happened. We open the file here so that this error checking is
604+ * done before we try to open the rest of the files to start copying etc.
605+ */
606+ out_fd = open(sieve_bctmpname, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
607+ if(out_fd < 0) {
608+ if(errno == EEXIST) {
609+ syslog(LOG_WARNING,"autocreate_sieve: File %s already exists. Probaly left over. Ignoring",sieve_bctmpname);
610+ } else if (errno == EACCES) {
611+ syslog(LOG_WARNING,"autocreate_sieve: No access to create file %s. Check permissions",sieve_bctmpname);
612+ fclose(in_stream);
613+ return 1;
614+ } else {
615+ syslog(LOG_WARNING,"autocreate_sieve: Unable to create %s. Unknown error",sieve_bctmpname);
616+ fclose(in_stream);
617+ return 1;
618+ }
619+ }
620+
621+ if(!do_compile && compiled_source_script && (in_fd = open(compiled_source_script, O_RDONLY)) != -1) {
622+ while((r = read(in_fd, buf, sizeof(buf))) > 0) {
623+ if((k=write(out_fd, buf,r)) < 0) {
624+ syslog(LOG_WARNING, "autocreate_sieve: Error writing to file: %s, error: %d", sieve_bctmpname, errno);
625+ close(out_fd);
626+ close(in_fd);
627+ fclose(in_stream);
628+ unlink(sieve_bctmpname);
629+ return 1;
630+ }
631+ }
632+
633+ if(r == 0) { /* EOF */
634+ close(out_fd);
635+ close(in_fd);
636+ } else if (r < 0) {
637+ syslog(LOG_WARNING, "autocreate_sieve: Error reading compiled script file: %s. Will try to compile it",
638+ compiled_source_script);
639+ close(in_fd);
640+ do_compile = 1;
641+ if(lseek(out_fd, 0, SEEK_SET)) {
642+ syslog(LOG_WARNING, "autocreate_sieve: Major IO problem. Aborting");
643+ return 1;
644+ }
645+ }
646+ close(in_fd);
647+ } else {
648+ if(compiled_source_script)
649+ syslog(LOG_WARNING,"autocreate_sieve: Problem opening compiled script file: %s. Compiling it", compiled_source_script);
650+ do_compile = 1;
651+ }
652+
653+
654+ /* Because we failed to open a precompiled bc sieve script, we compile one */
655+ if(do_compile) {
656+ if(is_script_parsable(in_stream,&err, &s) == TIMSIEVE_FAIL) {
657+ if(err && *err) {
658+ syslog(LOG_WARNING,"autocreate_sieve: Error while parsing script %s.",err);
659+ free(err);
660+ } else
661+ syslog(LOG_WARNING,"autocreate_sieve: Error while parsing script");
662+
663+ unlink(sieve_bctmpname);
664+ fclose(in_stream);
665+ close(out_fd);
666+ return 1;
667+ }
668+
669+ /* generate the bytecode */
670+ if(sieve_generate_bytecode(&bc, s) == TIMSIEVE_FAIL) {
671+ syslog(LOG_WARNING,"autocreate_sieve: problem compiling sieve script");
672+ /* removing the copied script and cleaning up memory */
673+ unlink(sieve_bctmpname);
674+ sieve_script_free(&s);
675+ fclose(in_stream);
676+ close(out_fd);
677+ return 1;
678+ }
679+
680+ if(sieve_emit_bytecode(out_fd, bc) == TIMSIEVE_FAIL) {
681+ syslog(LOG_WARNING,"autocreate_sieve: problem emiting sieve script");
682+ /* removing the copied script and cleaning up memory */
683+ unlink(sieve_bctmpname);
684+ sieve_free_bytecode(&bc);
685+ sieve_script_free(&s);
686+ fclose(in_stream);
687+ close(out_fd);
688+ return 1;
689+ }
690+
691+ /* clean up the memory */
692+ sieve_free_bytecode(&bc);
693+ sieve_script_free(&s);
694+ }
695+
696+ close(out_fd);
697+ rewind(in_stream);
698+
699+ /* Copy the initial script */
700+ oldmask = umask(077);
701+ if((out_fp = fopen(sieve_tmpname, "w")) == NULL) {
702+ syslog(LOG_WARNING,"autocreate_sieve: Unable to open %s destination sieve script", sieve_tmpname);
703+ unlink(sieve_bctmpname);
704+ umask(oldmask);
705+ fclose(in_stream);
706+ return 1;
707+ }
708+ umask(oldmask);
709+
710+ while((r = fread(buf,sizeof(char), sizeof(buf), in_stream))) {
711+ if( fwrite(buf,sizeof(char), r, out_fp) != r) {
712+ syslog(LOG_WARNING,"autocreate_sieve: Problem writing to sieve script file: %s",sieve_tmpname);
713+ fclose(out_fp);
714+ unlink(sieve_tmpname);
715+ unlink(sieve_bctmpname);
716+ fclose(in_stream);
717+ return 1;
718+ }
719+ }
720+
721+ if(feof(in_stream)) {
722+ fclose(out_fp);
723+ } else { /* ferror */
724+ fclose(out_fp);
725+ unlink(sieve_tmpname);
726+ unlink(sieve_bctmpname);
727+ fclose(in_stream);
728+ return 1;
729+ }
730+
731+ /* Renaming the necessary stuff */
732+ if(rename(sieve_tmpname, sieve_script_name)) {
733+ unlink(sieve_tmpname);
734+ unlink(sieve_bctmpname);
735+ return 1;
736+ }
737+
738+ if(rename(sieve_bctmpname, sieve_bcscript_name)) {
739+ unlink(sieve_bctmpname);
740+ unlink(sieve_bcscript_name);
741+ return 1;
742+ }
743+
744+ /* end now with the symlink */
745+ if(symlink(sieve_bclink_name, sieve_default)) {
746+ if(errno != EEXIST) {
747+ syslog(LOG_WARNING, "autocreate_sieve: problem making the default link.");
748+ /* Lets delete the files */
749+ unlink(sieve_script_name);
750+ unlink(sieve_bcscript_name);
751+ }
752+ }
753+
754+ /*
755+ * If everything has succeeded AND we have compiled the script AND we have requested
756+ * to generate the global script so that it is not compiled each time then we create it.
757+ */
758+ if(do_compile &&
759+ config_getswitch(IMAPOPT_GENERATE_COMPILED_SIEVE_SCRIPT)) {
760+
761+ if(!compiled_source_script) {
762+ syslog(LOG_WARNING, "autocreate_sieve: To save a compiled sieve script, autocreate_sieve_compiledscript must have been defined in imapd.conf");
763+ return 0;
764+ }
765+
766+ if(snprintf(sieve_tmpname, sizeof(sieve_tmpname), "%s.NEW", compiled_source_script) >= sizeof(sieve_tmpname))
767+ return 0;
768+
769+ /*
770+ * Copy everything from the newly created bc sieve sieve script.
771+ */
772+ if((in_fd = open(sieve_bcscript_name, O_RDONLY))<0) {
773+ return 0;
774+ }
775+
776+ if((out_fd = open(sieve_tmpname, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) < 0) {
777+ if(errno == EEXIST) {
778+ /* Someone is already doing this so just bail out. */
779+ syslog(LOG_WARNING, "autocreate_sieve: %s already exists. Some other instance processing it, or it is left over", sieve_tmpname);
780+ close(in_fd);
781+ return 0;
782+ } else if (errno == EACCES) {
783+ syslog(LOG_WARNING,"autocreate_sieve: No access to create file %s. Check permissions",sieve_tmpname);
784+ close(in_fd);
785+ return 0;
786+ } else {
787+ syslog(LOG_WARNING,"autocreate_sieve: Unable to create %s",sieve_tmpname);
788+ close(in_fd);
789+ return 0;
790+ }
791+ }
792+
793+ while((r = read(in_fd, buf, sizeof(buf))) > 0) {
794+ if((k = write(out_fd,buf,r)) < 0) {
795+ syslog(LOG_WARNING, "autocreate_sieve: Error writing to file: %s, error: %d", sieve_tmpname, errno);
796+ close(out_fd);
797+ close(in_fd);
798+ unlink(sieve_tmpname);
799+ return 0;
800+ }
801+ }
802+
803+ if(r == 0 ) { /*EOF */
804+ close(out_fd);
805+ close(in_fd);
806+ } else if (r < 0) {
807+ syslog(LOG_WARNING, "autocreate_sieve: Error writing to file: %s, error: %d", sieve_tmpname, errno);
808+ close(out_fd);
809+ close(in_fd);
810+ unlink(sieve_tmpname);
811+ return 0;
812+ }
813+
814+ /* Rename the temporary created sieve script to its final name. */
815+ if(rename(sieve_tmpname, compiled_source_script)) {
816+ if(errno != EEXIST) {
817+ unlink(sieve_tmpname);
818+ unlink(compiled_source_script);
819+ }
820+ return 0;
821+ }
822+
823+ syslog(LOG_NOTICE, "autocreate_sieve: Compiled sieve script was successfully saved in %s", compiled_source_script);
824+ }
825+
826+ return 0;
827+}
828+
829+static void fatal(const char *s, int code)
830+{
831+ printf("Fatal error: %s (%d)\r\n", s, code);
832+ exit(1);
833+}
834+
835+/* to make larry's stupid functions happy :) */
836+static void foo(void)
837+{
838+ fatal("stub function called", 0);
839+}
840+
841+static int sieve_notify(void *ac __attribute__((unused)),
842+ void *interp_context __attribute__((unused)),
843+ void *script_context __attribute__((unused)),
844+ void *message_context __attribute__((unused)),
845+ const char **errmsg __attribute__((unused)))
846+{
847+ fatal("stub function called", 0);
848+ return SIEVE_FAIL;
849+}
850+
851+static int mysieve_error(int lineno, const char *msg,
852+ void *i __attribute__((unused)), void *s)
853+{
854+ char buf[1024];
855+ char **errstr = (char **) s;
856+
857+ snprintf(buf, 80, "line %d: %s\r\n", lineno, msg);
858+ *errstr = (char *) xrealloc(*errstr, strlen(*errstr) + strlen(buf) + 30);
859+ syslog(LOG_DEBUG, "%s", buf);
860+ strcat(*errstr, buf);
861+
862+ return SIEVE_OK;
863+}
864+
865+/* end the boilerplate */
866+
867+/* returns TRUE or FALSE */
868+int is_script_parsable(FILE *stream, char **errstr, sieve_script_t **ret)
869+{
870+ sieve_interp_t *i;
871+ sieve_script_t *s;
872+ int res;
873+
874+ res = sieve_interp_alloc(&i, NULL);
875+ if (res != SIEVE_OK) {
876+ syslog(LOG_WARNING, "sieve_interp_alloc() returns %d\n", res);
877+ return TIMSIEVE_FAIL;
878+ }
879+
880+ res = sieve_register_redirect(i, (sieve_callback *) &foo);
881+ if (res != SIEVE_OK) {
882+ syslog(LOG_WARNING, "sieve_register_redirect() returns %d\n", res);
883+ return TIMSIEVE_FAIL;
884+ }
885+ res = sieve_register_discard(i, (sieve_callback *) &foo);
886+ if (res != SIEVE_OK) {
887+ syslog(LOG_WARNING, "sieve_register_discard() returns %d\n", res);
888+ return TIMSIEVE_FAIL;
889+ }
890+ res = sieve_register_reject(i, (sieve_callback *) &foo);
891+ if (res != SIEVE_OK) {
892+ syslog(LOG_WARNING, "sieve_register_reject() returns %d\n", res);
893+ return TIMSIEVE_FAIL;
894+ }
895+ res = sieve_register_fileinto(i, (sieve_callback *) &foo);
896+ if (res != SIEVE_OK) {
897+ syslog(LOG_WARNING, "sieve_register_fileinto() returns %d\n", res);
898+ return TIMSIEVE_FAIL;
899+ }
900+ res = sieve_register_keep(i, (sieve_callback *) &foo);
901+ if (res != SIEVE_OK) {
902+ syslog(LOG_WARNING, "sieve_register_keep() returns %d\n", res);
903+ return TIMSIEVE_FAIL;
904+ }
905+
906+ res = sieve_register_imapflags(i, NULL);
907+ if (res != SIEVE_OK) {
908+ syslog(LOG_WARNING, "sieve_register_imapflags() returns %d\n", res);
909+ return TIMSIEVE_FAIL;
910+ }
911+
912+ res = sieve_register_size(i, (sieve_get_size *) &foo);
913+ if (res != SIEVE_OK) {
914+ syslog(LOG_WARNING, "sieve_register_size() returns %d\n", res);
915+ return TIMSIEVE_FAIL;
916+ }
917+
918+ res = sieve_register_header(i, (sieve_get_header *) &foo);
919+ if (res != SIEVE_OK) {
920+ syslog(LOG_WARNING, "sieve_register_header() returns %d\n", res);
921+ return TIMSIEVE_FAIL;
922+ }
923+
924+ res = sieve_register_envelope(i, (sieve_get_envelope *) &foo);
925+ if (res != SIEVE_OK) {
926+ syslog(LOG_WARNING, "sieve_register_envelope() returns %d\n", res);
927+ return TIMSIEVE_FAIL;
928+ }
929+
930+ res = sieve_register_vacation(i, &vacation2);
931+ if (res != SIEVE_OK) {
932+ syslog(LOG_WARNING, "sieve_register_vacation() returns %d\n", res);
933+ return TIMSIEVE_FAIL;
934+ }
935+
936+ res = sieve_register_notify(i, &sieve_notify);
937+ if (res != SIEVE_OK) {
938+ syslog(LOG_WARNING, "sieve_register_notify() returns %d\n", res);
939+ return TIMSIEVE_FAIL;
940+ }
941+
942+ res = sieve_register_parse_error(i, &mysieve_error);
943+ if (res != SIEVE_OK) {
944+ syslog(LOG_WARNING, "sieve_register_parse_error() returns %d\n", res);
945+ return TIMSIEVE_FAIL;
946+ }
947+
948+ rewind(stream);
949+
950+ *errstr = (char *) xmalloc(20 * sizeof(char));
951+ strcpy(*errstr, "script errors:\r\n");
952+
953+ res = sieve_script_parse(i, stream, errstr, &s);
954+
955+ if (res == SIEVE_OK) {
956+ if(ret) {
957+ *ret = s;
958+ } else {
959+ sieve_script_free(&s);
960+ }
961+ free(*errstr);
962+ *errstr = NULL;
963+ }
964+
965+ /* free interpreter */
966+ sieve_interp_free(&i);
967+
968+ return (res == SIEVE_OK) ? TIMSIEVE_OK : TIMSIEVE_FAIL;
969+}
970+
971+/*
972+ * Btw the initial date of this patch is Sep, 02 2004 which is the birthday of
973+ * Pavlos. Author of cyrusmaster. So consider this patch as his birthday present
974+ */
975+
976diff -Naur cyrus-imapd-2.2.12/imap/compile_sieve.c cyrus-imapd-2.2.12.autocreate2/imap/compile_sieve.c
977--- cyrus-imapd-2.2.12/imap/compile_sieve.c 1970-01-01 02:00:00.000000000 +0200
978+++ cyrus-imapd-2.2.12.autocreate2/imap/compile_sieve.c 2005-10-19 14:48:57.943407000 +0300
979@@ -0,0 +1,364 @@
980+/* This tool compiles the sieve script from a command
981+line so that it can be used wby the autoadd patch */
982+#include <stdio.h>
983+#include <stdlib.h>
984+
985+#include <config.h>
986+#include <string.h>
987+#ifdef HAVE_UNISTD_H
988+#include <unistd.h>
989+#endif
990+#include <errno.h>
991+#include <sys/types.h>
992+#include <sys/stat.h>
993+#include <sys/uio.h>
994+#include <fcntl.h>
995+#include <ctype.h>
996+#include <time.h>
997+#include <com_err.h>
998+
999+#include "global.h"
1000+
1001+#include "util.h"
1002+#include "mailbox.h"
1003+#include "imap_err.h"
1004+#include "sieve_interface.h"
1005+#include "script.h"
1006+
1007+#include <pwd.h>
1008+
1009+#define TIMSIEVE_FAIL -1
1010+#define TIMSIEVE_OK 0
1011+#define MAX_FILENAME_SIZE 100
1012+
1013+/* Needed by libconfig */
1014+const int config_need_data = 0;
1015+
1016+static int is_script_parsable(FILE *stream, char **errstr, sieve_script_t **ret);
1017+
1018+static void fatal(const char *s, int code)
1019+{
1020+ printf("Fatal error: %s (%d)\r\n", s, code);
1021+
1022+ exit(1);
1023+}
1024+
1025+void usage(void)
1026+{
1027+ fprintf(stderr,
1028+ "Usage:\n\tcompile_sieve [-C <altconfig>] [-i <infile> -o <outfile>]\n");
1029+ exit(-1);
1030+}
1031+
1032+
1033+int main (int argc, char **argv)
1034+{
1035+
1036+ sieve_script_t *s = NULL;
1037+ bytecode_info_t *bc = NULL;
1038+ char *err = NULL;
1039+ FILE *in_stream;
1040+ int out_fd,r, k, opt;
1041+ char *source_script = NULL;
1042+ char *compiled_source_script = NULL;
1043+ mode_t oldmask;
1044+ struct stat statbuf;
1045+ char *alt_config = NULL;
1046+ extern char *optarg;
1047+ char sieve_tmpname[MAX_MAILBOX_NAME+1];
1048+
1049+ if (geteuid() == 0) fatal("must run as the Cyrus user", EC_USAGE);
1050+
1051+ while((opt = getopt(argc, argv, "C:i:o:")) != EOF) {
1052+ switch (opt) {
1053+ case 'C': /* alt config file */
1054+ alt_config = optarg;
1055+ break;
1056+ case 'i': /* input script file */
1057+ source_script = optarg;
1058+ break;
1059+ case 'o': /* output script file */
1060+ compiled_source_script = optarg;
1061+ break;
1062+ default:
1063+ usage();
1064+ break;
1065+ }
1066+ }
1067+
1068+ if(source_script && !compiled_source_script) {
1069+ fprintf(stderr, "No output file was defined\n");
1070+ usage();
1071+ } else if (!source_script && compiled_source_script) {
1072+ fprintf(stderr, "No input file was defined\n");
1073+ usage();
1074+ }
1075+
1076+ /*
1077+ * If no <infile> has been defined, then read them from
1078+ * the configuration file.
1079+ */
1080+ if (!source_script && !compiled_source_script) {
1081+ cyrus_init(alt_config, "compile_sieve", 0);
1082+
1083+ /* Initially check if we want to have the sieve script created */
1084+ if(!(source_script = (char *) config_getstring(IMAPOPT_AUTOCREATE_SIEVE_SCRIPT))) {
1085+ fprintf(stderr,"autocreate_sieve_script option not defined. Check imapd.conf\n");
1086+ return 1;
1087+ }
1088+
1089+ /* Check if we have an already compiled sieve script*/
1090+ if(!(compiled_source_script = (char *) config_getstring(IMAPOPT_AUTOCREATE_SIEVE_COMPILEDSCRIPT))) {
1091+ fprintf(stderr, "autocreate_sieve_compiledscript option not defined. Check imapd.conf\n");
1092+ return 1;
1093+ }
1094+
1095+ if(!strrchr(source_script,'/') || !strrchr(compiled_source_script,'/')) {
1096+ /*
1097+ * At this point the only think that is inconsistent is the directory
1098+ * that was created. But if the user will have any sieve scripts then
1099+ * they will eventually go there, so no big deal
1100+ */
1101+ fprintf(stderr,
1102+ "In imapd.conf the full path of the filenames must be defined\n");
1103+ return 1;
1104+ }
1105+ }
1106+
1107+ printf("input file : %s, output file : %s\n", source_script, compiled_source_script);
1108+
1109+
1110+ if(strlen(compiled_source_script) + sizeof(".NEW") + 1 > sizeof(sieve_tmpname)) {
1111+ fprintf(stderr, "Filename %s is too big\n", compiled_source_script);
1112+ return 1;
1113+ }
1114+
1115+ snprintf(sieve_tmpname, sizeof(sieve_tmpname), "%s.NEW", compiled_source_script);
1116+
1117+ in_stream = fopen(source_script,"r");
1118+
1119+ if(!in_stream) {
1120+ fprintf(stderr,"Unable to open %s source sieve script\n",source_script);
1121+ return;
1122+ }
1123+
1124+ /*
1125+ * We open the file that will be used as the bc file. If this file exists, overwrite it
1126+ * since something bad has happened. We open the file here so that this error checking is
1127+ * done before we try to open the rest of the files to start copying etc.
1128+ */
1129+ out_fd = open(sieve_tmpname, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
1130+ if(out_fd < 0) {
1131+ if(errno == EEXIST) {
1132+ fprintf(stderr, "File %s already exists\n", sieve_tmpname);
1133+ } else if (errno == EACCES) {
1134+ fprintf(stderr,"No access to create file %s. Please check that you have the correct permissions\n",
1135+ sieve_tmpname);
1136+ } else {
1137+ fprintf(stderr,"Unable to create %s. Please check that you have the correct permissions\n",
1138+ sieve_tmpname);
1139+ }
1140+
1141+ fclose(in_stream);
1142+ return 1;
1143+ }
1144+
1145+ if(is_script_parsable(in_stream,&err, &s) == TIMSIEVE_FAIL) {
1146+ if(err && *err) {
1147+ fprintf(stderr, "Error while parsing script %s\n",err);
1148+ free(err);
1149+ }
1150+ else
1151+ fprintf(stderr,"Error while parsing script\n");
1152+ unlink(sieve_tmpname);
1153+ fclose(in_stream);
1154+ close(out_fd);
1155+ return;
1156+ }
1157+
1158+
1159+ /* generate the bytecode */
1160+ if(sieve_generate_bytecode(&bc,s) == TIMSIEVE_FAIL) {
1161+ fprintf(stderr,"Error occured while compiling sieve script\n");
1162+ /* removing the copied script and cleaning up memory */
1163+ unlink(sieve_tmpname);
1164+ sieve_script_free(&s);
1165+ fclose(in_stream);
1166+ close(out_fd);
1167+ return;
1168+ }
1169+ if(sieve_emit_bytecode(out_fd,bc) == TIMSIEVE_FAIL) {
1170+ fprintf(stderr, "Error occured while emitting sieve script\n");
1171+ unlink(sieve_tmpname);
1172+ sieve_free_bytecode(&bc);
1173+ sieve_script_free(&s);
1174+ fclose(in_stream);
1175+ close(out_fd);
1176+ return;
1177+ }
1178+
1179+ /* clean up the memory */
1180+ sieve_free_bytecode(&bc);
1181+ sieve_script_free(&s);
1182+
1183+ close(out_fd);
1184+
1185+ if(rename(sieve_tmpname, compiled_source_script)) {
1186+ if(errno != EEXIST) {
1187+ unlink(sieve_tmpname);
1188+ unlink(compiled_source_script);
1189+ return 1;
1190+ }
1191+ }
1192+ return 0;
1193+}
1194+
1195+
1196+/* to make larry's stupid functions happy :) */
1197+static void foo(void)
1198+{
1199+ fatal("stub function called", 0);
1200+}
1201+
1202+extern sieve_vacation_t vacation2;/* = {
1203+ 0, / min response /
1204+ 0, / max response /
1205+ (sieve_callback *) &foo, / autorespond() /
1206+ (sieve_callback *) &foo / send_response() /
1207+}; */
1208+
1209+static int sieve_notify(void *ac __attribute__((unused)),
1210+ void *interp_context __attribute__((unused)),
1211+ void *script_context __attribute__((unused)),
1212+ void *message_context __attribute__((unused)),
1213+ const char **errmsg __attribute__((unused)))
1214+{
1215+ fatal("stub function called", 0);
1216+ return SIEVE_FAIL;
1217+}
1218+
1219+static int mysieve_error(int lineno, const char *msg,
1220+ void *i __attribute__((unused)), void *s)
1221+{
1222+ char buf[1024];
1223+ char **errstr = (char **) s;
1224+
1225+ snprintf(buf, 80, "line %d: %s\r\n", lineno, msg);
1226+ *errstr = (char *) xrealloc(*errstr, strlen(*errstr) + strlen(buf) + 30);
1227+ fprintf(stderr, "%s\n", buf);
1228+ strcat(*errstr, buf);
1229+
1230+ return SIEVE_OK;
1231+}
1232+
1233+/* end the boilerplate */
1234+
1235+/* returns TRUE or FALSE */
1236+int is_script_parsable(FILE *stream, char **errstr, sieve_script_t **ret)
1237+{
1238+ sieve_interp_t *i;
1239+ sieve_script_t *s;
1240+ int res;
1241+
1242+ res = sieve_interp_alloc(&i, NULL);
1243+ if (res != SIEVE_OK) {
1244+ fprintf(stderr, "sieve_interp_alloc() returns %d\n", res);
1245+ return TIMSIEVE_FAIL;
1246+ }
1247+
1248+ res = sieve_register_redirect(i, (sieve_callback *) &foo);
1249+ if (res != SIEVE_OK) {
1250+ fprintf(stderr, "sieve_register_redirect() returns %d\n", res);
1251+ return TIMSIEVE_FAIL;
1252+ }
1253+ res = sieve_register_discard(i, (sieve_callback *) &foo);
1254+ if (res != SIEVE_OK) {
1255+ fprintf(stderr, "sieve_register_discard() returns %d\n", res);
1256+ return TIMSIEVE_FAIL;
1257+ }
1258+ res = sieve_register_reject(i, (sieve_callback *) &foo);
1259+ if (res != SIEVE_OK) {
1260+ fprintf(stderr, "sieve_register_reject() returns %d\n", res);
1261+ return TIMSIEVE_FAIL;
1262+ }
1263+ res = sieve_register_fileinto(i, (sieve_callback *) &foo);
1264+ if (res != SIEVE_OK) {
1265+ fprintf(stderr, "sieve_register_fileinto() returns %d\n", res);
1266+ return TIMSIEVE_FAIL;
1267+ }
1268+ res = sieve_register_keep(i, (sieve_callback *) &foo);
1269+ if (res != SIEVE_OK) {
1270+ fprintf(stderr, "sieve_register_keep() returns %d\n", res);
1271+ return TIMSIEVE_FAIL;
1272+ }
1273+
1274+ res = sieve_register_imapflags(i, NULL);
1275+ if (res != SIEVE_OK) {
1276+ fprintf(stderr, "sieve_register_imapflags() returns %d\n", res);
1277+ return TIMSIEVE_FAIL;
1278+ }
1279+
1280+ res = sieve_register_size(i, (sieve_get_size *) &foo);
1281+ if (res != SIEVE_OK) {
1282+ fprintf(stderr, "sieve_register_size() returns %d\n", res);
1283+ return TIMSIEVE_FAIL;
1284+ }
1285+
1286+ res = sieve_register_header(i, (sieve_get_header *) &foo);
1287+ if (res != SIEVE_OK) {
1288+ fprintf(stderr, "sieve_register_header() returns %d\n", res);
1289+ return TIMSIEVE_FAIL;
1290+ }
1291+
1292+ res = sieve_register_envelope(i, (sieve_get_envelope *) &foo);
1293+ if (res != SIEVE_OK) {
1294+ fprintf(stderr, "sieve_register_envelope() returns %d\n", res);
1295+ return TIMSIEVE_FAIL;
1296+ }
1297+
1298+ res = sieve_register_vacation(i, &vacation2);
1299+ if (res != SIEVE_OK) {
1300+ fprintf(stderr, "sieve_register_vacation() returns %d\n", res);
1301+ return TIMSIEVE_FAIL;
1302+ }
1303+
1304+ res = sieve_register_notify(i, &sieve_notify);
1305+ if (res != SIEVE_OK) {
1306+ fprintf(stderr, "sieve_register_notify() returns %d\n", res);
1307+ return TIMSIEVE_FAIL;
1308+ }
1309+
1310+ res = sieve_register_parse_error(i, &mysieve_error);
1311+ if (res != SIEVE_OK) {
1312+ fprintf(stderr, "sieve_register_parse_error() returns %d\n", res);
1313+ return TIMSIEVE_FAIL;
1314+ }
1315+
1316+ rewind(stream);
1317+
1318+ *errstr = (char *) xmalloc(20 * sizeof(char));
1319+ strcpy(*errstr, "script errors:\r\n");
1320+
1321+ res = sieve_script_parse(i, stream, errstr, &s);
1322+
1323+ if (res == SIEVE_OK) {
1324+ if(ret) {
1325+ *ret = s;
1326+ } else {
1327+ sieve_script_free(&s);
1328+ }
1329+ free(*errstr);
1330+ *errstr = NULL;
1331+ }
1332+
1333+ /* free interpreter */
1334+ sieve_interp_free(&i);
1335+
1336+ return (res == SIEVE_OK) ? TIMSIEVE_OK : TIMSIEVE_FAIL;
1337+}
1338+
1339+
1340+
1341+
1342+
1343+
1344diff -Naur cyrus-imapd-2.2.12/imap/imapd.c cyrus-imapd-2.2.12.autocreate2/imap/imapd.c
1345--- cyrus-imapd-2.2.12/imap/imapd.c 2005-02-14 08:39:55.000000000 +0200
1346+++ cyrus-imapd-2.2.12.autocreate2/imap/imapd.c 2005-10-19 14:48:57.966749000 +0300
1347@@ -158,6 +158,7 @@
1348 void motd_file(int fd);
1349 void shut_down(int code);
1350 void fatal(const char *s, int code);
1351+void autocreate_inbox(void);
1352
1353 void cmdloop(void);
1354 void cmd_login(char *tag, char *user);
1355@@ -1693,6 +1694,42 @@
1356 }
1357
1358 /*
1359+ * Autocreate Inbox and subfolders upon login
1360+ */
1361+void autocreate_inbox()
1362+{
1363+ char inboxname[MAX_MAILBOX_NAME+1];
1364+ int autocreatequota;
1365+ int r;
1366+
1367+ /*
1368+ * Exlude admin's accounts
1369+ */
1370+ if (imapd_userisadmin || imapd_userisproxyadmin)
1371+ return;
1372+
1373+ /*
1374+ * Exclude anonymous
1375+ */
1376+ if (!strcmp(imapd_userid, "anonymous"))
1377+ return;
1378+
1379+ if ((autocreatequota = config_getint(IMAPOPT_AUTOCREATEQUOTA))) {
1380+ /* This is actyally not required
1381+ as long as the lenght of userid is ok */
1382+ r = (*imapd_namespace.mboxname_tointernal) (&imapd_namespace,
1383+ "INBOX", imapd_userid, inboxname);
1384+ if (!r)
1385+ r = mboxlist_lookup(inboxname, NULL, NULL, NULL);
1386+
1387+ if (r == IMAP_MAILBOX_NONEXISTENT)
1388+ mboxlist_autocreateinbox(&imapd_namespace, imapd_userid,
1389+ imapd_authstate, inboxname, autocreatequota);
1390+ }
1391+}
1392+
1393+
1394+/*
1395 * Perform a LOGIN command
1396 */
1397 void cmd_login(char *tag, char *user)
1398@@ -1848,6 +1885,9 @@
1399 strcspn(imapd_userid, "@") : 0);
1400
1401 freebuf(&passwdbuf);
1402+
1403+ autocreate_inbox();
1404+
1405 return;
1406 }
1407
1408@@ -1993,6 +2033,8 @@
1409 config_virtdomains ?
1410 strcspn(imapd_userid, "@") : 0);
1411
1412+ autocreate_inbox();
1413+
1414 return;
1415 }
1416
1417diff -Naur cyrus-imapd-2.2.12/imap/lmtpd.c cyrus-imapd-2.2.12.autocreate2/imap/lmtpd.c
1418--- cyrus-imapd-2.2.12/imap/lmtpd.c 2004-12-17 18:32:15.000000000 +0200
1419+++ cyrus-imapd-2.2.12.autocreate2/imap/lmtpd.c 2005-10-19 14:48:57.971145000 +0300
1420@@ -106,6 +106,8 @@
1421 static FILE *spoolfile(message_data_t *msgdata);
1422 static void removespool(message_data_t *msgdata);
1423
1424+static int autocreate_inbox(char *rcpt_userid);
1425+
1426 /* current namespace */
1427 static struct namespace lmtpd_namespace;
1428
1429@@ -504,10 +506,55 @@
1430 exit(code);
1431 }
1432
1433+/*
1434+ * Autocreate Inbox and subfolders upon login
1435+ */
1436+int autocreate_inbox(char *rcpt_userid)
1437+{
1438+ struct auth_state *authstate;
1439+ char inboxname[MAX_MAILBOX_NAME+1];
1440+ int rcptisadmin;
1441+ int autocreatequota;
1442+ int r;
1443+
1444+ if(rcpt_userid == NULL)
1445+ return IMAP_MAILBOX_NONEXISTENT;
1446+
1447+ /*
1448+ * Exclude anonymous
1449+ */
1450+ if (!strcmp(rcpt_userid, "anonymous"))
1451+ return IMAP_MAILBOX_NONEXISTENT;
1452+
1453+ /*
1454+ * Check for autocreatequota and createonpost
1455+ */
1456+ if (!(autocreatequota = config_getint(IMAPOPT_AUTOCREATEQUOTA)) ||
1457+ !(config_getswitch(IMAPOPT_CREATEONPOST)))
1458+ return IMAP_MAILBOX_NONEXISTENT;
1459+
1460+ /*
1461+ * Exclude admin's accounts
1462+ */
1463+ authstate = auth_newstate(rcpt_userid);
1464+ rcptisadmin = global_authisa(authstate, IMAPOPT_ADMINS);
1465+ if (rcptisadmin)
1466+ return IMAP_MAILBOX_NONEXISTENT;
1467+
1468+ r = (*lmtpd_namespace.mboxname_tointernal) (&lmtpd_namespace,
1469+ "INBOX", rcpt_userid, inboxname);
1470+ if (!r)
1471+ r = mboxlist_autocreateinbox(&lmtpd_namespace, rcpt_userid,
1472+ authstate, inboxname, autocreatequota);
1473+ return r;
1474+}
1475+
1476+
1477 static int verify_user(const char *user, const char *domain, const char *mailbox,
1478 long quotacheck, struct auth_state *authstate)
1479 {
1480 char namebuf[MAX_MAILBOX_NAME+1] = "";
1481+ char *userinbox = NULL;
1482 int r = 0;
1483
1484 if ((!user && !mailbox) ||
1485@@ -545,6 +592,28 @@
1486 */
1487 r = append_check(namebuf, MAILBOX_FORMAT_NORMAL, authstate,
1488 !user ? ACL_POST : 0, quotacheck > 0 ? 0 : quotacheck);
1489+ if (r == IMAP_MAILBOX_NONEXISTENT && user) {
1490+ if(domain) {
1491+ int k;
1492+ userinbox = (char *)xmalloc((strlen(user)+strlen(domain)+2)*sizeof(char));
1493+ k = strlcpy(userinbox, user, strlen(user)+1);
1494+ *(userinbox + k) = '@';
1495+ strlcpy(userinbox+k+1, domain, strlen(domain)+1);
1496+ }
1497+ else userinbox = user;
1498+ /*
1499+ * Try to create automatically the mailbox, if
1500+ * autocreate inbox option is enabled.
1501+ */
1502+ r = autocreate_inbox(userinbox);
1503+
1504+ if(userinbox != user)
1505+ free(userinbox);
1506+ if (!r)
1507+ r = append_check(namebuf, MAILBOX_FORMAT_NORMAL, authstate,
1508+ 0, quotacheck > 0 ? 0 : quotacheck);
1509+ }
1510+
1511 }
1512
1513 if (r) syslog(LOG_DEBUG, "verify_user(%s) failed: %s", namebuf,
1514diff -Naur cyrus-imapd-2.2.12/imap/mboxlist.c cyrus-imapd-2.2.12.autocreate2/imap/mboxlist.c
1515--- cyrus-imapd-2.2.12/imap/mboxlist.c 2004-07-26 21:08:03.000000000 +0300
1516+++ cyrus-imapd-2.2.12.autocreate2/imap/mboxlist.c 2005-10-19 14:49:25.972032000 +0300
1517@@ -81,6 +81,12 @@
1518 #include "mboxlist.h"
1519 #include "quota.h"
1520
1521+#ifdef USE_SIEVE
1522+extern int autoadd_sieve(char *userid,
1523+ const char *source_script);
1524+#endif
1525+
1526+
1527 #define DB config_mboxlist_db
1528 #define SUBDB config_subscription_db
1529
1530@@ -98,11 +104,29 @@
1531 static int mboxlist_changequota(const char *name, int matchlen, int maycreate,
1532 void *rock);
1533
1534+static int mboxlist_autochangesub(char *name, int matchlen, int maycreate,
1535+ void *rock);
1536+
1537+static int mboxlist_autosubscribe_sharedfolders(struct namespace *namespace,
1538+ char *userid, char *auth_userid,
1539+ struct auth_state *auth_state);
1540+
1541 struct change_rock {
1542 struct quota *quota;
1543 struct txn **tid;
1544 };
1545
1546+/*
1547+ * Struct needed to be passed as void *rock to
1548+ * mboxlist_autochangesub();
1549+ */
1550+struct changesub_rock_st {
1551+ char *userid;
1552+ char *auth_userid;
1553+ struct auth_state *auth_state;
1554+};
1555+
1556+
1557 #define FNAME_SUBSSUFFIX ".sub"
1558
1559 /*
1560@@ -3124,3 +3148,338 @@
1561
1562 return DB->abort(mbdb, tid);
1563 }
1564+
1565+/*
1566+ * Automatically subscribe user to *ALL* shared folders,
1567+ * one has permissions to be subscribed to.
1568+ * INBOX subfolders are excluded.
1569+ */
1570+static int mboxlist_autochangesub(char *name, int matchlen, int maycreate,
1571+ void *rock) {
1572+
1573+ struct changesub_rock_st *changesub_rock = (struct changesub_rock_st *) rock;
1574+ char *userid = changesub_rock->userid;
1575+ char *auth_userid = changesub_rock->auth_userid;
1576+ struct auth_state *auth_state = changesub_rock->auth_state;
1577+ int r;
1578+
1579+
1580+ if((strlen(name) == 5 && !strncmp(name, "INBOX", 5)) || /* Exclude INBOX */
1581+ (strlen(name) > 5 && !strncmp(name, "INBOX.",6)) || /* Exclude INBOX subfolders */
1582+ (strlen(name) > 4 && !strncmp(name, "user.", 5))) /* Exclude other users' folders */
1583+ return 0;
1584+
1585+
1586+ r = mboxlist_changesub(name, userid, auth_state, 1, 0);
1587+
1588+ if (r) {
1589+ syslog(LOG_WARNING,
1590+ "autosubscribe: User %s to folder %s, subscription failed: %s",
1591+ auth_userid, name, error_message(r));
1592+ } else {
1593+ syslog(LOG_NOTICE,
1594+ "autosubscribe: User %s to folder %s, subscription succeeded",
1595+ auth_userid, name);
1596+ }
1597+
1598+ return 0;
1599+}
1600+
1601+#define SEP '|'
1602+
1603+/*
1604+ * Automatically subscribe user to a shared folder.
1605+ * Subscription is done successfully, if the shared
1606+ * folder exists and the user has the necessary
1607+ * permissions.
1608+ */
1609+static int mboxlist_autosubscribe_sharedfolders(struct namespace *namespace,
1610+ char *userid, char *auth_userid,
1611+ struct auth_state *auth_state) {
1612+
1613+ const char *sub ;
1614+ char *p, *q, *next_sub;
1615+ char folder[MAX_MAILBOX_NAME+1], name[MAX_MAILBOX_NAME+1], mailboxname[MAX_MAILBOX_NAME+1];
1616+ int len;
1617+ int r = 0;
1618+ int subscribe_all_sharedfolders = 0;
1619+
1620+ subscribe_all_sharedfolders = config_getswitch(IMAPOPT_AUTOSUBSCRIBE_ALL_SHAREDFOLDERS);
1621+
1622+ /*
1623+ * If subscribeallsharedfolders is set to yes in imapd.conf, then
1624+ * subscribe user to every shared folder one has the apropriate
1625+ * permissions.
1626+ */
1627+ if(subscribe_all_sharedfolders) {
1628+ char pattern[MAX_MAILBOX_PATH+1];
1629+ struct changesub_rock_st changesub_rock;
1630+
1631+ strcpy(pattern, "*");
1632+ changesub_rock.userid = userid;
1633+ changesub_rock.auth_userid = auth_userid;
1634+ changesub_rock.auth_state = auth_state;
1635+
1636+ r = mboxlist_findall(namespace, pattern, 0, userid,
1637+ auth_state, mboxlist_autochangesub, &changesub_rock);
1638+
1639+ return r;
1640+ }
1641+
1642+ if ((sub=config_getstring(IMAPOPT_AUTOSUBSCRIBESHAREDFOLDERS)) == NULL)
1643+ return r;
1644+
1645+ next_sub = (char *) sub;
1646+ while (*next_sub) {
1647+ for (p = next_sub ; isspace((int) *p) || *p == SEP ; p++);
1648+ for (next_sub = p ; *next_sub && *next_sub != SEP ; next_sub++);
1649+ for (q = next_sub ; q > p && (isspace((int) *q) || *q == SEP || !*q) ; q--);
1650+ if (!*p ) continue;
1651+
1652+ len = q - p + 1;
1653+ /* Check for folder length */
1654+ if (len > sizeof(folder)-1)
1655+ continue;
1656+
1657+ if (!r) {
1658+ strncpy(folder, p, len);
1659+ folder[len] = '\0';
1660+
1661+ strlcpy(name, namespace->prefix[NAMESPACE_SHARED], sizeof(name));
1662+ len = strlcat(name, folder, sizeof(name));
1663+
1664+ r = (namespace->mboxname_tointernal) (namespace, name, userid,
1665+ mailboxname);
1666+ }
1667+
1668+ if (!r)
1669+ r = mboxlist_changesub(mailboxname, userid, auth_state, 1, 0);
1670+
1671+ if (!r) {
1672+ syslog(LOG_NOTICE, "autosubscribe: User %s to %s succeeded",
1673+ userid, folder);
1674+ } else {
1675+ syslog(LOG_WARNING, "autosubscribe: User %s to %s failed: %s",
1676+ userid, folder, error_message(r));
1677+ r = 0;
1678+ }
1679+ }
1680+
1681+ return r;
1682+}
1683+
1684+
1685+
1686+int mboxlist_autocreateinbox(struct namespace *namespace,
1687+ char *userid,
1688+ struct auth_state *auth_state,
1689+ char *mailboxname, int autocreatequota) {
1690+ char name [MAX_MAILBOX_NAME+1];
1691+ char folder [MAX_MAILBOX_NAME+1];
1692+ char *auth_userid = NULL;
1693+ char *partition = NULL;
1694+ const char *crt;
1695+ const char *sub;
1696+ char *p, *q, *next_crt, *next_sub;
1697+ int len;
1698+ int r = 0;
1699+ int numcrt = 0;
1700+ int numsub = 0;
1701+#ifdef USE_SIEVE
1702+ const char *source_script;
1703+#endif
1704+
1705+ /*
1706+ * While this is not needed for admins
1707+ * and imap_admins accounts, it would be
1708+ * better to separate *all* admins and
1709+ * proxyservers from normal accounts
1710+ * (accounts that have mailboxes).
1711+ * UOA Specific note(1): Even if we do not
1712+ * exclude these servers-classes here,
1713+ * UOA specific code, will neither return
1714+ * role, nor create INBOX, because none of these
1715+ * administrative accounts belong to the
1716+ * mailRecipient objectclass, or have imapPartition.
1717+ * UOA Specific note(2): Another good reason for doing
1718+ * this, is to prevent the code, from getting into
1719+ * cyrus_ldap.c because of the continues MSA logins to LMTPd.
1720+ */
1721+
1722+ /*
1723+ * admins and the coresponding imap
1724+ * service, had already been excluded.
1725+ */
1726+
1727+ /*
1728+ * Do we really need group membership
1729+ * for admins or service_admins?
1730+ */
1731+ if (global_authisa(auth_state, IMAPOPT_ADMINS)) return 0;
1732+ if (global_authisa(auth_state, IMAPOPT_ADMINS)) return 0;
1733+
1734+ /*
1735+ * Do we really need group membership
1736+ * for proxyservers?
1737+ */
1738+ if (global_authisa(auth_state, IMAPOPT_PROXYSERVERS)) return 0;
1739+ if (global_authisa(auth_state, IMAPOPT_PROXYSERVERS)) return 0;
1740+
1741+ auth_userid = auth_canonuser(auth_state);
1742+
1743+ if (auth_userid == NULL) {
1744+ /*
1745+ * Couldn't get cannon userid
1746+ */
1747+ syslog(LOG_ERR,
1748+ "Could not get cannon userid for user %s", userid);
1749+ return IMAP_PARTITION_UNKNOWN;
1750+ }
1751+
1752+#if 0
1753+ /*
1754+ * Get Partition info or return.
1755+ * (Here you should propably use
1756+ * you own "get_partition(char *userid)"
1757+ * function. Otherwise all new INBOXes will be
1758+ * created into whatever partition has been declared
1759+ * as default in your imapd.conf)
1760+ */
1761+
1762+ partition = get_partition(userid);
1763+
1764+ if (partition == NULL) {
1765+ /*
1766+ * Couldn't get partition info
1767+ */
1768+ syslog(LOG_ERR,
1769+ "Could not get imapPartition info for user %s", userid);
1770+ return IMAP_PARTITION_UNKNOWN;
1771+ }
1772+#endif
1773+
1774+ r = mboxlist_createmailbox(mailboxname, MAILBOX_FORMAT_NORMAL, NULL,
1775+ 1, userid, auth_state, 0, 0, 0);
1776+
1777+ if (!r && autocreatequota > 0)
1778+ r = mboxlist_setquota(mailboxname, autocreatequota, 0);
1779+
1780+ if (!r)
1781+ r = mboxlist_changesub(mailboxname, userid,
1782+ auth_state, 1, 1);
1783+
1784+ if (!r) {
1785+ syslog(LOG_NOTICE, "autocreateinbox: User %s, INBOX was successfully created in partition %s",
1786+ auth_userid, partition == NULL ? "default" : partition);
1787+ } else {
1788+ syslog(LOG_ERR, "autocreateinbox: User %s, INBOX failed. %s",
1789+ auth_userid, error_message(r));
1790+ }
1791+
1792+
1793+#if 0
1794+ /* Allocated from get_partition, and not needed any more */
1795+ free_partition(partition);
1796+#endif
1797+
1798+ if (r) return r;
1799+
1800+
1801+ /* INBOX's subfolders */
1802+ if ((crt=config_getstring(IMAPOPT_AUTOCREATEINBOXFOLDERS)))
1803+ sub=config_getstring(IMAPOPT_AUTOSUBSCRIBEINBOXFOLDERS);
1804+
1805+ /* Roll through crt */
1806+ next_crt = (char *) crt;
1807+ while (next_crt!=NULL && *next_crt) {
1808+ for (p = next_crt ; isspace((int) *p) || *p == SEP ; p++);
1809+ for (next_crt = p ; *next_crt && *next_crt != SEP ; next_crt++);
1810+ for (q = next_crt ; q > p && (isspace((int) *q) || *q == SEP || !*q); q--);
1811+
1812+ if (!*p) continue;
1813+
1814+ len = q - p + 1;
1815+
1816+ /* First time we check for length */
1817+ if (len > sizeof(folder) - 5)
1818+ r = IMAP_MAILBOX_BADNAME;
1819+
1820+ if (!r) {
1821+ strncpy(folder, p, len);
1822+ folder[len] = '\0';
1823+
1824+ strlcpy(name, namespace->prefix[NAMESPACE_INBOX], sizeof(name));
1825+ len = strlcat(name, folder, sizeof(name));
1826+ }
1827+
1828+ if (!r)
1829+ r = (namespace->mboxname_tointernal) (namespace, name, userid,
1830+ mailboxname);
1831+ if (!r)
1832+ r = mboxlist_createmailbox(mailboxname, MAILBOX_FORMAT_NORMAL, NULL,
1833+ 1, userid, auth_state, 0, 0, 0);
1834+
1835+ if (!r) {
1836+ numcrt++;
1837+ syslog(LOG_NOTICE, "autocreateinbox: User %s, subfolder %s creation succeeded.",
1838+ auth_userid, name);
1839+ } else {
1840+ syslog(LOG_WARNING, "autocreateinbox: User %s, subfolder %s creation failed. %s",
1841+ auth_userid, name, error_message(r));
1842+ r=0;
1843+ continue;
1844+ }
1845+
1846+ /* Roll through sub */
1847+ next_sub = (char *) sub;
1848+ while (next_sub!=NULL && *next_sub) {
1849+ for (p = next_sub ; isspace((int) *p) || *p == SEP ; p++);
1850+ for (next_sub = p ; *next_sub && *next_sub != SEP ; next_sub++);
1851+ for (q = next_sub ; q > p && (isspace((int) *q) || *q == SEP || !*q) ; q--);
1852+ if (!*p ) continue;
1853+
1854+ len = q - p + 1;
1855+
1856+ if (len != strlen(folder) || strncmp(folder, p, len))
1857+ continue;
1858+
1859+ r = mboxlist_changesub(mailboxname, userid, auth_state, 1, 1);
1860+
1861+ if (!r) {
1862+ numsub++;
1863+ syslog(LOG_NOTICE,"autocreateinbox: User %s, subscription to %s succeeded",
1864+ auth_userid, name);
1865+ } else
1866+ syslog(LOG_WARNING, "autocreateinbox: User %s, subscription to %s failed. %s",
1867+ auth_userid, name, error_message(r));
1868+
1869+ break;
1870+ }
1871+ }
1872+
1873+ if (crt!=NULL && *crt)
1874+ syslog(LOG_INFO, "User %s, Inbox subfolders, created %d, subscribed %d",
1875+ auth_userid, numcrt, numsub);
1876+
1877+ /*
1878+ * Check if shared folders are available for subscription.
1879+ */
1880+ mboxlist_autosubscribe_sharedfolders(namespace, userid, auth_userid, auth_state);
1881+
1882+#ifdef USE_SIEVE
1883+ /*
1884+ * Here the autocreate sieve script feature is iniated from.
1885+ */
1886+ source_script = config_getstring(IMAPOPT_AUTOCREATE_SIEVE_SCRIPT);
1887+
1888+ if (source_script) {
1889+ if (!autoadd_sieve(userid, source_script))
1890+ syslog(LOG_NOTICE, "autocreate_sieve: User %s, default sieve script creation succeeded", auth_userid);
1891+ else
1892+ syslog(LOG_WARNING, "autocreate_sieve: User %s, default sieve script creation failed", auth_userid);
1893+ }
1894+#endif
1895+
1896+ return r;
1897+}
1898+
1899diff -Naur cyrus-imapd-2.2.12/imap/mboxlist.h cyrus-imapd-2.2.12.autocreate2/imap/mboxlist.h
1900--- cyrus-imapd-2.2.12/imap/mboxlist.h 2004-03-17 20:07:49.000000000 +0200
1901+++ cyrus-imapd-2.2.12.autocreate2/imap/mboxlist.h 2005-10-19 14:48:58.027033000 +0300
1902@@ -197,4 +197,10 @@
1903 int mboxlist_commit(struct txn *tid);
1904 int mboxlist_abort(struct txn *tid);
1905
1906+int mboxlist_autocreateinbox(struct namespace *namespace,
1907+ char *userid,
1908+ struct auth_state *auth_state,
1909+ char *mailboxname, int autocreatequota);
1910+
1911+
1912 #endif
1913diff -Naur cyrus-imapd-2.2.12/imap/pop3d.c cyrus-imapd-2.2.12.autocreate2/imap/pop3d.c
1914--- cyrus-imapd-2.2.12/imap/pop3d.c 2005-01-04 17:06:13.000000000 +0200
1915+++ cyrus-imapd-2.2.12.autocreate2/imap/pop3d.c 2005-10-19 14:48:58.033335000 +0300
1916@@ -152,6 +152,8 @@
1917 static char popd_apop_chal[45 + MAXHOSTNAMELEN + 1]; /* <rand.time@hostname> */
1918 static void cmd_apop(char *response);
1919
1920+static int autocreate_inbox(char *inboxname, char *userid);
1921+
1922 static void cmd_auth(char *arg);
1923 static void cmd_capa(void);
1924 static void cmd_pass(char *pass);
1925@@ -1084,6 +1086,7 @@
1926 popd_userid = xstrdup(p);
1927 prot_printf(popd_out, "+OK Name is a valid mailbox\r\n");
1928 }
1929+
1930 }
1931
1932 void cmd_pass(char *pass)
1933@@ -1328,6 +1331,46 @@
1934 }
1935
1936 /*
1937+ * Autocreate Inbox and subfolders upon login
1938+ */
1939+int autocreate_inbox(char *inboxname, char *auth_userid)
1940+{
1941+ struct auth_state *authstate;
1942+ int userisadmin;
1943+ int autocreatequota;
1944+ int r;
1945+
1946+ if(inboxname == NULL || auth_userid == NULL)
1947+ return IMAP_MAILBOX_NONEXISTENT;
1948+
1949+ /*
1950+ * Exclude anonymous
1951+ */
1952+ if (!strcmp(popd_userid, "anonymous"))
1953+ return IMAP_MAILBOX_NONEXISTENT;
1954+
1955+ /*
1956+ * Check for autocreatequota
1957+ */
1958+ if (!(autocreatequota = config_getint(IMAPOPT_AUTOCREATEQUOTA)))
1959+ return IMAP_MAILBOX_NONEXISTENT;
1960+
1961+ /*
1962+ * Exclude admin's accounts
1963+ */
1964+
1965+ authstate = auth_newstate(popd_userid);
1966+ userisadmin = global_authisa(authstate, IMAPOPT_ADMINS);
1967+ if (userisadmin)
1968+ return IMAP_MAILBOX_NONEXISTENT;
1969+
1970+ r = mboxlist_autocreateinbox(&popd_namespace, auth_userid,
1971+ authstate, inboxname, autocreatequota);
1972+ return r;
1973+}
1974+
1975+
1976+/*
1977 * Complete the login process by opening and locking the user's inbox
1978 */
1979 int openinbox(void)
1980@@ -1349,6 +1392,10 @@
1981 userid, inboxname);
1982
1983 if (!r) r = mboxlist_detail(inboxname, &type, NULL, &server, &acl, NULL);
1984+ /* Try once again after autocreate_inbox */
1985+ if (r == IMAP_MAILBOX_NONEXISTENT && !(r = autocreate_inbox(inboxname, userid)))
1986+ r = mboxlist_detail(inboxname, &type, NULL, &server, &acl, NULL);
1987+
1988 if (!r && (config_popuseacl = config_getswitch(IMAPOPT_POPUSEACL)) &&
1989 (!acl ||
1990 !((myrights = cyrus_acl_myrights(popd_authstate, acl)) & ACL_READ))) {
1991diff -Naur cyrus-imapd-2.2.12/lib/auth.h cyrus-imapd-2.2.12.autocreate2/lib/auth.h
1992--- cyrus-imapd-2.2.12/lib/auth.h 2003-10-22 21:50:12.000000000 +0300
1993+++ cyrus-imapd-2.2.12.autocreate2/lib/auth.h 2005-10-19 14:48:58.035324000 +0300
1994@@ -60,4 +60,6 @@
1995 extern struct auth_state *auth_newstate(const char *identifier);
1996 extern void auth_freestate(struct auth_state *auth_state);
1997
1998+extern char *auth_canonuser(struct auth_state *auth_state);
1999+
2000 #endif /* INCLUDED_AUTH_H */
2001diff -Naur cyrus-imapd-2.2.12/lib/auth_krb.c cyrus-imapd-2.2.12.autocreate2/lib/auth_krb.c
2002--- cyrus-imapd-2.2.12/lib/auth_krb.c 2003-11-11 05:26:00.000000000 +0200
2003+++ cyrus-imapd-2.2.12.autocreate2/lib/auth_krb.c 2005-10-19 14:48:58.038180000 +0300
2004@@ -338,3 +338,11 @@
2005 free((char *)auth_state);
2006 }
2007
2008+char *
2009+auth_canonuser(struct auth_state *auth_state)
2010+{
2011+ if (auth_state)
2012+ return auth_state->userid;
2013+ return NULL;
2014+}
2015+
2016diff -Naur cyrus-imapd-2.2.12/lib/auth_krb5.c cyrus-imapd-2.2.12.autocreate2/lib/auth_krb5.c
2017--- cyrus-imapd-2.2.12/lib/auth_krb5.c 2004-01-16 17:28:58.000000000 +0200
2018+++ cyrus-imapd-2.2.12.autocreate2/lib/auth_krb5.c 2005-10-19 14:48:58.040108000 +0300
2019@@ -193,4 +193,11 @@
2020 free(auth_state);
2021 }
2022
2023+char *
2024+auth_canonuser(struct auth_state *auth_state)
2025+{
2026+ if (auth_state)
2027+ return auth_state->userid;
2028+ return NULL;
2029+}
2030
2031diff -Naur cyrus-imapd-2.2.12/lib/auth_pts.c cyrus-imapd-2.2.12.autocreate2/lib/auth_pts.c
2032--- cyrus-imapd-2.2.12/lib/auth_pts.c 2004-02-25 01:11:37.000000000 +0200
2033+++ cyrus-imapd-2.2.12.autocreate2/lib/auth_pts.c 2005-10-19 14:48:58.042343000 +0300
2034@@ -349,3 +349,11 @@
2035 {
2036 free(auth_state);
2037 }
2038+
2039+char *auth_canonuser(struct auth_state *auth_state)
2040+{
2041+ if (auth_state)
2042+ return auth_state->userid.id;
2043+ return NULL;
2044+}
2045+
2046diff -Naur cyrus-imapd-2.2.12/lib/auth_unix.c cyrus-imapd-2.2.12.autocreate2/lib/auth_unix.c
2047--- cyrus-imapd-2.2.12/lib/auth_unix.c 2004-09-14 01:49:29.000000000 +0300
2048+++ cyrus-imapd-2.2.12.autocreate2/lib/auth_unix.c 2005-10-19 14:48:58.044431000 +0300
2049@@ -267,4 +267,11 @@
2050 free((char *)auth_state);
2051 }
2052
2053+char *auth_canonuser(struct auth_state *auth_state)
2054+{
2055+ if (auth_state)
2056+ return auth_state->userid;
2057+
2058+ return NULL;
2059+}
2060
2061diff -Naur cyrus-imapd-2.2.12/lib/imapoptions cyrus-imapd-2.2.12.autocreate2/lib/imapoptions
2062--- cyrus-imapd-2.2.12/lib/imapoptions 2004-07-21 22:07:45.000000000 +0300
2063+++ cyrus-imapd-2.2.12.autocreate2/lib/imapoptions 2005-10-19 14:48:58.048748000 +0300
2064@@ -169,6 +169,51 @@
2065 /* Number of seconds to wait before returning a timeout failure when
2066 performing a client connection (e.g. in a murder enviornment) */
2067
2068+{ "createonpost", 0, SWITCH }
2069+/* If yes, when lmtpd receives an incoming mail for an INBOX that does not exist,
2070+ then the INBOX is automatically created by lmtpd. */
2071+
2072+{ "autocreateinboxfolders", NULL, STRING }
2073+/* If a user does not have an INBOX created then the INBOX as well as some INBOX subfolders are
2074+ created under two conditions.
2075+ 1. The user logins via the IMAP or the POP3 protocol. (autocreatequota option must have a nonzero value)
2076+ 2. A message arrives for the user through the LMTPD protocol.(createonpost option must yes)
2077+ autocreateinboxfolders is a list of INBOX's subfolders separated by a "|", that are automatically created by the server
2078+ under the previous two situations. */
2079+
2080+{ "autosubscribeinboxfolders", NULL, STRING }
2081+/* A list of folder names, separated by "|" that the users get automatically subscribed to, when their INBOX
2082+ is created.
2083+ These folder names must have been included in the autocreateinboxfolders option of the imapd.conf. */
2084+
2085+{ "autosubscribesharedfolders", NULL, STRING }
2086+/* A list of shared folders (bulletin boards), separated by "|" that the users get
2087+ automatically subscribed to, after their INBOX
2088+ is created. The shared folder must have been created and the user must have the
2089+ required permissions to get subscribed to the it. Otherwise the subscription fails. */
2090+
2091+{ "autosubscribe_all_sharedfolders", 0, SWITCH }
2092+/* If set to yes then the user is automatically subscribed to all shared folders, one has permission
2093+ to subscribe to. */
2094+
2095+{ "autocreate_sieve_script", NULL, STRING }
2096+/* The full path of a file that contains a sieve script. This script automatically becomes a
2097+ user's initial default sieve filter script. When this option is not defined, no default
2098+ sieve filter is created. The file must be readable by the cyrus daemon. */
2099+
2100+{ "autocreate_sieve_compiledscript", NULL, STRING }
2101+/* The full path of a file that contains a compiled in bytecode sieve script. This script
2102+ automatically becomes a user's initial default sieve filter script.
2103+ If this option is not specified, or the filename doesn't exist then the script defined
2104+ by autocreate_sieve_script is compiled on the fly and installed as the user's default
2105+ sieve script */
2106+
2107+{ "generate_compiled_sieve_script", 0, SWITCH }
2108+/* If set to yes and no compiled sieve script file exists then the sieve script that is
2109+ compiled on the fly will be saved in the file name that autocreate_sieve_compiledscript
2110+ option points. In order a compiled script to be generated, autocreate_sieve_script and
2111+ autocreate_sieve_compiledscript must have valid values */
2112+
2113 { "configdirectory", NULL, STRING }
2114 /* The pathname of the IMAP configuration directory. This field is
2115 required. */
2116diff -Naur cyrus-imapd-2.2.12/notifyd/Makefile.in cyrus-imapd-2.2.12.autocreate2/notifyd/Makefile.in
2117--- cyrus-imapd-2.2.12/notifyd/Makefile.in 2004-05-28 21:03:06.000000000 +0300
2118+++ cyrus-imapd-2.2.12.autocreate2/notifyd/Makefile.in 2005-10-19 14:48:58.050575000 +0300
2119@@ -69,10 +69,11 @@
2120 SERVICE=../master/service.o
2121
2122 IMAP_LIBS = @IMAP_LIBS@ @LIB_RT@
2123+SIEVE_LIBS = @SIEVE_LIBS@
2124 IMAP_COM_ERR_LIBS = @IMAP_COM_ERR_LIBS@
2125 LIB_WRAP = @LIB_WRAP@
2126 LIBS = @ZEPHYR_LIBS@ @LIBS@ $(IMAP_COM_ERR_LIBS)
2127-DEPLIBS=../imap/mutex_fake.o ../imap/libimap.a ../lib/libcyrus.a ../lib/libcyrus_min.a @DEPLIBS@
2128+DEPLIBS=../imap/mutex_fake.o ../imap/libimap.a $(SIEVE_LIBS) ../lib/libcyrus.a ../lib/libcyrus_min.a @DEPLIBS@
2129
2130 PURIFY=/usr/local/bin/purify
2131 PUREOPT=-best-effort
2132diff -Naur cyrus-imapd-2.2.12/notifyd/notifyd.c cyrus-imapd-2.2.12.autocreate2/notifyd/notifyd.c
2133--- cyrus-imapd-2.2.12/notifyd/notifyd.c 2004-12-17 18:32:25.000000000 +0200
2134+++ cyrus-imapd-2.2.12.autocreate2/notifyd/notifyd.c 2005-10-19 14:48:58.052220000 +0300
2135@@ -97,7 +97,7 @@
2136
2137 #define NOTIFY_MAXSIZE 8192
2138
2139-int do_notify()
2140+static int do_notify()
2141 {
2142 struct sockaddr_un sun_data;
2143 socklen_t sunlen = sizeof(sun_data);
2144diff -Naur cyrus-imapd-2.2.12/ptclient/Makefile.in cyrus-imapd-2.2.12.autocreate2/ptclient/Makefile.in
2145--- cyrus-imapd-2.2.12/ptclient/Makefile.in 2004-05-28 21:03:08.000000000 +0300
2146+++ cyrus-imapd-2.2.12.autocreate2/ptclient/Makefile.in 2005-10-19 14:48:58.053762000 +0300
2147@@ -57,10 +57,11 @@
2148 AFS_LDFLAGS = @AFS_LDFLAGS@ @COM_ERR_LDFLAGS@
2149 AFS_LIBS = @AFS_LIBS@
2150 IMAP_LIBS = @IMAP_LIBS@ @LIB_RT@
2151+SIEVE_LIBS = @SIEVE_LIBS@
2152 LIBS = $(IMAP_LIBS) @COM_ERR_LIBS@
2153 LIB_SASL = @LIB_SASL@
2154 LIB_WRAP = @LIB_WRAP@
2155-DEPLIBS = ../imap/libimap.a ../lib/libcyrus.a ../lib/libcyrus_min.a @DEPLIBS@
2156+DEPLIBS = ../imap/libimap.a $(SIEVE_LIBS) ../lib/libcyrus.a ../lib/libcyrus_min.a @DEPLIBS@
2157 UTIL_LIBS = ../imap/mutex_fake.o ../imap/cli_fatal.o
2158
2159 LDAP_LIBS=@LDAP_LIBS@