~ubuntu-dev/ubuntu/lucid/dovecot/lucid-201002101901

« back to all changes in this revision

Viewing changes to debian/patches/dovecot-MANAGESIEVE-9.3.dpatch

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short
  • Date: 2008-05-26 09:51:01 UTC
  • mfrom: (1.10.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20080526095101-y0zxqc8ofd9j1aa5
Tags: 1:1.0.13-4ubuntu1
* Merge from debian unstable, remaining changes:
  - DebainMaintainerField
  - Use Snakeoil SSL certificate by default.
    + debian/control: Depend on ssl-cert
    + debian/patches/ssl-cert-snakeoil.dpatch: Change default SSL cert paths
      to snakeoil.
    + debian/dovecot-common.postinst: Relax grep for SSL_* a bit.
  - Fast TearDown:
    + debian/rules: Call dh_installinit in 'multiuser' mode.
    + debian/control: Depend on newer sysv-rc for this.
    + debian/dovecot-common.postinst: Remove stp script symlinks from rc0 and rc6 on upgrades.
      Need to be kept unil next LTS release.
  - Add autopkgtest in debian/tests/*.
  - Don't fail in postinst if dovecot-{sql,ldap} is missing. (LP: #153161)
  - Dropped upstream-mail-group-fixes.dpatch. No longer needed.
  - Dropped upstream-invalid-password-fixes.dpatch. No longer needed.
  - debian/dovecot-common.init: Check to see if there is an /etc/inetd.conf. (LP: #208411)
  - debian/patches/login-max-processes-count-warning.dpatch: Tell the user
    that they have reached the maxium number of processes count. (LP: #189616)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#! /bin/sh -e
 
2
 
 
3
## ManageSieve patch v9.3 for dovecot-1.0.13.
 
4
## 
 
5
## Copyright (c) 2006-2008 by Stephan Bosch <stephan@rename-it.nl>
 
6
## 
 
7
## This patch is made for and partly based on the Dovecot Secure IMAP server
 
8
## written by Timo Sirainen <tss@iki.fi>. The managesieve service is a modified
 
9
## version of Dovecot's imap service implementation.
 
10
## 
 
11
## This patch includes the CMU Sieve sources copyrighted by the Carnegie Mellon
 
12
## University. The authors are listed (after patching) at:
 
13
##   src/lib-sieve/cmu/libsieve/AUTHORS
 
14
## 
 
15
## This patch is licenced under LGPLv2.1 (see COPYING.LGPL in the dovecot sources)
 
16
## 
 
17
## The included CMU Sieve code is licenced under a custom Carnegie Mellon
 
18
## University licence as explained in the respective source files in:
 
19
##   src/lib-sieve/cmu/libsieve/
 
20
## 
 
21
 
 
22
. $(dirname $0)/DPATCH
 
23
 
 
24
exit 0
 
25
@DPATCH@
 
26
diff -r 894f003d9f5f README.managesieve
 
27
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
28
+++ b/README.managesieve        Sun May 04 16:00:59 2008 +0200
 
29
@@ -0,0 +1,372 @@
 
30
+Dovecot-MANAGESIEVE patch v9.3 for dovecot-1.0
 
31
+
 
32
+Compile
 
33
+-------
 
34
+
 
35
+After applying this patch, the usual ./configure, make, make install sequence 
 
36
+is not enough. First the automake/autoconf structure needs to be rebuilt to 
 
37
+include the ManageSieve sources in the compilation process. This requires 
 
38
+autotools to be installed on your system. 
 
39
+
 
40
+When you downloaded using Mercurial you have script called autogen.sh in your
 
41
+source tree. And you should proceed as specified on:
 
42
+
 
43
+http://wiki.dovecot.org/CompilingSource
 
44
+
 
45
+Otherwise, execute the following command inside the dovecot source tree:
 
46
+
 
47
+autoreconf -i
 
48
+
 
49
+After this you can continue the usual build process
 
50
+(http://wiki.dovecot.org/CompilingSource):
 
51
+
 
52
+./configure
 
53
+make
 
54
+sudo make install 
 
55
 
56
+Configure
 
57
+---------
 
58
+
 
59
+**NOTE**: If you have used the sieve plugin before and you have .dovecot.sieve 
 
60
+files in user directories, you are advised to make a backup first. Although the 
 
61
+managesieve daemon takes care to move these files to the sieve storage before it 
 
62
+is substituted with a symbolic link, this is not a very well tested operation, 
 
63
+meaning that there is a possibility that existing sieve scripts get lost.
 
64
+
 
65
+Along with all other binaries that dovecot uses, the managesieve and 
 
66
+managesieve-login binaries are installed during make install. The only thing you 
 
67
+need to do to activate the ManageSieve support in dovecot is to add managesieve 
 
68
+to the protocols= configuration line in your dovecot.conf. The managesieve 
 
69
+daemon will listen on port 2000 by default. As the implementation of the 
 
70
+managesieve daemon is largely based on the original IMAP implementation, it is 
 
71
+very similar in terms of configuration. In addition to most mail daemon config 
 
72
+settings, the managesieve daemon accepts a few more. The following settings can 
 
73
+be configured in the protocol managesieve section:
 
74
+
 
75
+listen = *:2000
 
76
+    IP or host address where to listen in for connections. 
 
77
+
 
78
+login_executable = /usr/libexec/dovecot/managesieve-login
 
79
+    Login executable location. 
 
80
+
 
81
+mail_executable = /usr/libexec/dovecot/managesieve
 
82
+    managesieve executable location. See mail_executable for IMAP for examples 
 
83
+    how this could be changed. 
 
84
+    
 
85
+managesieve_max_line_length = 65536
 
86
+    Maximum managesieve command line length in bytes. This setting is directly 
 
87
+    borrowed from IMAP. But, since long command lines are very unlikely with 
 
88
+    ManageSieve, changing this will not be very useful. 
 
89
+
 
90
+sieve_storage =
 
91
+    This specifies the path to the directory where the uploaded scripts are 
 
92
+    stored. In terms of '%' variable substitution it is identical to dovecot's 
 
93
+    mail_location setting used by the mail protocol daemons. Scripts are stored 
 
94
+    as separate files with extension .sieve, all other files are ignored when 
 
95
+    scripts are listed by a ManageSieve client. If this setting remains 
 
96
+    unspecified, the mail_location setting is used as explained below. 
 
97
+
 
98
+sieve = ~/.dovecot.sieve
 
99
+    Specifies the location of the symbolic link pointing to the active script in
 
100
+    the sieve storage directory. This must match the sieve setting used by 
 
101
+    deliver. Variable substitution with % is recognized. If a regular file 
 
102
+    exists at this location, it is moved to the sieve_storage location before 
 
103
+    the symbolic link is installed. It is renamed to dovecot.orig.sieve and 
 
104
+    therefore listed as dovecot.orig by a ManageSieve client. 
 
105
+
 
106
+mail_location =
 
107
+    If, for some inobvious reason, the sieve_storage remains unset, the 
 
108
+    managesieve daemon uses the specification of the mail_location to find out 
 
109
+    where to store the sieve files. However, this is provided only for backwards 
 
110
+    compatibility and you should always use the sieve_storage setting in stead. 
 
111
+
 
112
+managesieve_implementation_string = dovecot
 
113
+    To fool ManageSieve clients that are focused on CMU's timesieved you can 
 
114
+    specify the IMPLEMENTATION capability that the dovecot reports to clients 
 
115
+    (e.g. 'Cyrus timsieved v2.2.13'). 
 
116
+
 
117
+Scripts are stored at the location specified by the sieve_storage setting. The
 
118
+active sieve script is managed as a symbolic link pointing to the active script
 
119
+in the sieve storage direcotory. The location of this symlink can be specified
 
120
+with the 'sieve' setting. Make sure this setting is identical to what deliver is
 
121
+using for the Sieve plugin. The default location is ~/.dovecot.sieve. Note that
 
122
+if a file starting with '.' is placed inside a Maildir, it will be recognized as
 
123
+a folder, so try to avoid that.
 
124
+
 
125
+The current version of the managesieve daemon places the script storage 
 
126
+directory in the mail folder as specified by the 'mail_location' setting if no 
 
127
+'sieve_storage' is specified. Actually, it is placed in the CONTROL= directory 
 
128
+of 'mail_location' if specified, otherwise the sieve directory is placed in the 
 
129
+root of the mail location. In a mail or mail control directory, scripts are 
 
130
+always stored in a 'sieve' subdirectory. Note that for some mail storage types 
 
131
+(e.g. mbox) this script directory is listed as a mail folder, so be sure to put 
 
132
+the sieve scripts somewhere else if you can.
 
133
+
 
134
+A storage location specified by 'sieve_storage' is always generated 
 
135
+automatically if it does not exist (as far as the system permits the user to do 
 
136
+so; no root privileges are used). This is similar to the behaviour of the mail 
 
137
+daemons. Note that when 'mail_location' is used to specify the script storage 
 
138
+location, only the 'sieve' subdirectory is generated automatically.
 
139
+
 
140
+The following provides an example configuration for ManageSieve in dovecot.conf. 
 
141
+Only sections relevant to ManageSieve are shown. Refer to dovecot-example.conf 
 
142
+in your patched dovecot tree for a full example with comments, but don't forget 
 
143
+to add managesieve to the protocols setting if you use it.
 
144
+
 
145
+# Start imap, pop3 and managesieve services
 
146
+protocols = imap pop3 managesieve
 
147
+
 
148
+protocol managesieve {
 
149
+  # Specify an alternative address:port the daemon must listen on
 
150
+  # (default: *:2000)
 
151
+  #listen = localhost:2000
 
152
+
 
153
+  sieve=~/.dovecot.sieve
 
154
+  sieve_storage=~/sieve
 
155
+}
 
156
+
 
157
+Proxying
 
158
+--------
 
159
+
 
160
+Like Dovecot's imapd, the ManageSieve login daemon supports proxying to multiple
 
161
+backend servers. Although the underlying code is copied from the imapd sources
 
162
+for the most part, it has some ManageSieve-specifics that have not seen much
 
163
+testing. 
 
164
+
 
165
+The proxy configuration wiki page for POP3 and IMAP should apply to ManageSieve 
 
166
+as well:
 
167
+
 
168
+http://wiki.dovecot.org/PasswordDatabase/ExtraFields/Proxy
 
169
+
 
170
+Known Issues
 
171
+------------
 
172
+
 
173
+* Although this ManageSieve server should comply with the draft specification of 
 
174
+  the ManageSieve protocol, quite a few clients don't. This is particularly true 
 
175
+  for the TLS support. However, now that Cyrus' Timsieved has changed its 
 
176
+  behavior towards protocol compliance, all those clients will follow 
 
177
+  eventually. 
 
178
+
 
179
+  Clients known to have TLS issues:
 
180
+       - Thunderbird Sieve add-on: author is working on it
 
181
+       - AvelSieve: patch on the wiki: http://wiki.dovecot.org/ManageSieve
 
182
+       - KMail + kio_sieve: ...?
 
183
+
 
184
+  Unfortunately, there is no reliable way to provide a workaround for this
 
185
+  problem. We will have to wait for the authors of these clients to make the
 
186
+  proper adjustments. 
 
187
+  
 
188
+* Other client issues:
 
189
+
 
190
+       - SmartSieve, WebSieve: 
 
191
+           These clients are specifically written for Cyrus timsieved and fail on 
 
192
+           multiple stages of the protocol when connected to Dovecot ManageSieve.
 
193
+           
 
194
+* The current implementation of the daemon does not have quota enforcement as
 
195
+  recommended in the specification. So keep in mind that malicious users could
 
196
+  fill your filesystem with loads of spurious scriptfiles.
 
197
+  
 
198
+* The ANONYMOUS authentication mechanism is currently not supported and 
 
199
+  explicitly denied. 
 
200
+
 
201
+Contact Info
 
202
+------------
 
203
+
 
204
+Stephan Bosch <stephan at rename-it dot nl>
 
205
+IRC: Freenode, #dovecot, S[r]us
 
206
+
 
207
+Please use the Dovecot mailing list <dovecot at dovecot.org> for questions about 
 
208
+this package. You can post to the list without subscribing, the mail then waits 
 
209
+in a moderator queue for a while. See http://dovecot.org/mailinglists.html
 
210
+
 
211
+Design
 
212
+------
 
213
+
 
214
+The overall design of the daemon is entirely borrowed from the existing
 
215
+imap daemon. I have tried to apply the dovecot framework and programming
 
216
+paradigms as much as possible. This patch adds the following directories
 
217
+to the source directory:
 
218
+
 
219
+lib-managesieve: parser and quote functions (bound to disappear)
 
220
+lib-sievestorage: defines a storage for the sieve scripts (a bit crude)
 
221
+managesieve-login: the initial login daemon (derived from src/imap-login)
 
222
+managesieve: the actual managesieve daemon (derived form src/imap)
 
223
+lib-sieve: yet another copy of the cmu sieve library :/ (fixed for Dovecot 1.1)
 
224
+
 
225
+Currently the managesieve daemon simply plugs in the dovecot-master as any
 
226
+other mail protocol (imap,pop3). Since managesieve is not actually a mail
 
227
+protocol, this is probably not a good design practice. However, i designed
 
228
+this patch to be most uninvasive to the existing sources. I think Timo 
 
229
+knows best how to implement this link properly.
 
230
+
 
231
+The daemon currently implements all existing MANAGESIEVE commands except the 
 
232
+HAVESPACE command which always says 'ok'. It also implements the required
 
233
+support for UTF-8 strings. 
 
234
+
 
235
+Changelog
 
236
+---------
 
237
+
 
238
+* v9.3
 
239
+- Fixed bug that caused SASL mechanisms that require more than a single client
 
240
+  response to fail. Reported by Steffen Kaiser and occured when he tried using 
 
241
+  the (obsolete) LOGIN mechanism.
 
242
+  information provided in the wiki
 
243
+
 
244
+* v9.2
 
245
+- Fixed bug in tmp file generation for sieve-storage: errors other than EEXIST
 
246
+  would cause the daemon to sleep() loop indefinitely.
 
247
+  managesieve.
 
248
+
 
249
+* v9.1
 
250
+
 
251
+* V9
 
252
+  very time-constrained and thus hard to reproduce. The error turned out
 
253
+  to be related to the input handling of the login daemon during 
 
254
+  authentication. 
 
255
+  managesieve implementation due to code duplication.
 
256
+  the storage was moved. 
 
257
+  places. 
 
258
+  sieve storage. 
 
259
+  in this file more concise. 
 
260
+
 
261
+* V8
 
262
+  in" message is now sent by the -login process and not by the managesieve 
 
263
+  daemon anymore. This caused a segfault every once in a while. 
 
264
+  login_dir. 'dovecot -n' now reports correct results, but testing will show
 
265
+  whether the whole problem is solved.
 
266
+  settings, so it is now possible to explicitly configure the location of the
 
267
+  sieve storage and the active script respectively. The daemon still falls back
 
268
+  to using the mail_location (MAIL) settings if nothing else is specified. 
 
269
+  clients have adopted to this behaviour. The latest managesieve (08) advises to
 
270
+  accept a missing + from clients. The server should not send any + characters 
 
271
+  as well. This behavior is now implemented on the server. 
 
272
+  various sub-functions for obtaining the various paths and directories.
 
273
+  path fails somehow. Previously, this presented the admin with a log message 
 
274
+  that it had just eaten the script, which is not very nice. 
 
275
+  regard to the configuration of the daemon.
 
276
+
 
277
+* V7 
 
278
+- Robin Breathe indicated that the regex capability was missing in the server's
 
279
+  SIEVE listing. It turns out I forgot to make arrangements for setting 
 
280
+  ENABLE_REGEX in the cmu libsieve sources, so the regex extension was not
 
281
+  compiled in. I copied the configure.in section regarding ENABLE_REGEX from 
 
282
+  dovecot-sieve-1.0.2 and that fixed the problem.
 
283
+
 
284
+* V6
 
285
+- Corked the client output stream while producing the capability greeting and on 
 
286
+  other some other occasions as well. Some naive client implementations expect to 
 
287
+  receive this as a single tcp frame and it is a good practice to do so anyway.
 
288
+  Using this change the Thunderbird sieve extension (v0.1.1) seemed to work. However,
 
289
+  scripts larger than a tcp frame still caused failures. All these issues are fixed
 
290
+  in the latest version of the sieve add-on (currently v0.1.4). 
 
291
+- Cleaned up the new proxy source. My editor made the indentation a complete mess
 
292
+  in terms of TABs vs spaces. 
 
293
+- Added TRYLATER response codes to BYE and NO messages where appropriate.  
 
294
+- Recopied the libsieve library into this patch to incorporate any changes that were
 
295
+  made (only sieve-cmu.c still needs to be compared to the old cmu-sieve.c). This 
 
296
+  also solves the __attribute__((unused)) GCC dependencies. These were fixed long
 
297
+  ago by Timo....  the code duplication beast strikes again. 
 
298
+- Removed spurious return value from void function in 
 
299
+  src/lib-sieve/sieve-implementation.c as reported by Robin Breathe. GCC fails to
 
300
+  report these issues. The function involved is currently not used and serves only
 
301
+  as an example on how dovecot could support multiple sieve backends... 
 
302
+
 
303
+* V5 
 
304
+- Applied patch by Uldis Pakuls to fix master_dump_settings bug
 
305
+- Added some compilation/installation info to this README
 
306
+- Moved README to source tree root as README.managesieve
 
307
+- Fixed minor error handling bug in sieve_storage.c with respect to a missing
 
308
+  root directory.
 
309
+- Now sieve capabilities are reported as they are specified by the implementing
 
310
+  library and not in forced upper case. The sieve RFC now explicitly states
 
311
+  that sieve capability identifiers are case-sensitive. This broke compatibility
 
312
+  with SquirrelMail/Avelsieve. 
 
313
+- Disabled ANONYMOUS login entirely until proper support is implemented. V4
 
314
+  claimed to do so as well, but in fact it only stopped announcing it.
 
315
+- Implemented managesieve-proxy. It is not so much a clean copy of imap-proxy,
 
316
+  since the managesieve greeting is much more complex and requires parsing. 
 
317
+  Configuration is identical to imap-proxy. This seems to be a little under-
 
318
+  documented however (http://wiki.dovecot.org/PasswordDatabase/ExtraFields).  
 
319
+
 
320
+* V4
 
321
+- Added managesieve_implementation_string setting to the managesieve 
 
322
+  configuration. This can be used to customize the default "IMPLEMENTATION" 
 
323
+  capability response.
 
324
+- Denied ANONYMOUS login until proper support is implemented
 
325
+- Fixed problem with authenticate command regarding continued responses. In
 
326
+  V3 only initial response would work. Problem was caused by rc2 -> rc28 
 
327
+  upgrade. One of the clear reasons why code duplication is a very bad idea.
 
328
+- Fixed readlink bug as indicated by Timo: return value of readlink can also
 
329
+  be -1.
 
330
+- Fixed bug in the regular file rescue code, as introduced in the previous 
 
331
+  version. Used stat instead of lstat. This caused the symlink to be rescued 
 
332
+  subsequently in the next activation, thus still overwriting the initially 
 
333
+  rescued script.
 
334
+
 
335
+* V3
 
336
+- Updated source to compile with dovecot 1.0.rc27 
 
337
+- Daemon now uses the same location for .dovecot.sieve as dovecot-lda
 
338
+  This is typically ~/.dovecot.sieve
 
339
+- If .dovecot.sieve is a regular file, it is now moved into the script storage as
 
340
+  dovecot.orig.sieve, preventing deletion of (important) active scripts 
 
341
+  upon upgrade.
 
342
+- Changed error handling to yield a BYE message when the managesieve 
 
343
+  daemon exits unexpectedly (upon login) before any commands are entered. 
 
344
+  Horde-ingo would wait indefinitely for a response. 
 
345
+
 
346
+* V2
 
347
+- Fixed the bug (missing CRLF) in the authenticate command
 
348
+- Modified the sieve storage library making the interface much less crude.
 
349
+- The scripts put on the server using the putscript command are now 
 
350
+  checked before they are accepted.
 
351
+- The reported SIEVE capability is now directly read from the sieve 
 
352
+  implementation (in this case cmu), listing much more than "FILEINTO 
 
353
+  VACATION".
 
354
+- Imported instance of libsieve source into this patch for implementation
 
355
+  of script checking and capability listing. THIS NEEDS TO BE CHANGED! 
 
356
+- Fixed some minor bugs in the putscript command
 
357
+
 
358
+TODO
 
359
+------------
 
360
+
 
361
+* Upgrade to dovecot-1.1 branch. 
 
362
+* Enforce protocol syntax better with some of the commands. Some 
 
363
+  commands still allow spurious extra arguments
 
364
+  --> Full protocol syntax conformance review. 
 
365
+* Implement proper support for anonymous login.
 
366
+* Implement listing of NOTIFY capability as specified in the latest versions
 
367
+  of the MANAGESIEVE draft.
 
368
+* Implement the HAVESPACE command properly. Currently it always says ok.
 
369
+  Maybe this should be linked to the mail quota system that is currently 
 
370
+  developed. 
 
371
+* Create proper process interface for generic non-mail protocols (Timo).
 
372
+* Resolve exessive code duplication
 
373
+* Uploaded scripts are syntax checked, but this patch includes another 
 
374
+  cmu-sieve source tree to implement this. This needs to be put in some
 
375
+  unified location in de dovecot(-sieve) tree. This will probably have to
 
376
+  wait until dovecot v2.0
 
377
+* Make the sieve storage a base class with (possibly) various 
 
378
+  implementations, just like mail-storage. Currently not very useful. 
 
379
+
 
380
+* Thorough testing...
 
381
+
 
382
diff -r 894f003d9f5f configure.in
 
383
--- a/configure.in      Sun Mar 09 12:50:11 2008 +0200
 
384
+++ b/configure.in      Sun May 04 16:00:59 2008 +0200
 
385
@@ -9,6 +9,8 @@ AC_ISC_POSIX
 
386
 AC_ISC_POSIX
 
387
 AC_PROG_CC
 
388
 AC_PROG_CPP
 
389
+AM_PROG_LEX
 
390
+AC_PROG_YACC
 
391
 AC_HEADER_STDC
 
392
 AC_C_INLINE
 
393
 AC_PROG_LIBTOOL
 
394
@@ -287,6 +289,16 @@ AC_ARG_WITH(pop3d,
 
395
        fi,
 
396
        want_pop3d=yes)
 
397
 AM_CONDITIONAL(BUILD_POP3D, test "$want_pop3d" = "yes")
 
398
+
 
399
+AC_ARG_WITH(managesieve,
 
400
+[  --with-managesieve      Build MANAGESIEVE server (default)],
 
401
+  if test x$withval = xno; then
 
402
+    want_managesieve=no
 
403
+  else
 
404
+    want_managesieve=yes
 
405
+  fi,
 
406
+  want_managesieve=yes)
 
407
+AM_CONDITIONAL(BUILD_MANAGESIEVE, test "$want_managesieve" = "yes")
 
408
 
 
409
 AC_ARG_WITH(deliver,
 
410
 [  --with-deliver          Build mail delivery agent (default)],
 
411
@@ -1812,6 +1824,11 @@ capability="IMAP4rev1 SASL-IR SORT THREA
 
412
 capability="IMAP4rev1 SASL-IR SORT THREAD=REFERENCES MULTIAPPEND UNSELECT LITERAL+ IDLE CHILDREN NAMESPACE LOGIN-REFERRALS"
 
413
 AC_DEFINE_UNQUOTED(CAPABILITY_STRING, "$capability", IMAP capabilities)
 
414
 
 
415
+dnl * Regexp library check, from Cyrus IMAP
 
416
+AC_SEARCH_LIBS(regcomp, rx regex, [
 
417
+  CFLAGS="$CFLAGS -DENABLE_REGEX"
 
418
+  AC_CHECK_HEADER(rxposix.h, CFLAGS="$CFLAGS -DHAVE_RX")])
 
419
+
 
420
 CFLAGS="$CFLAGS $EXTRA_CFLAGS"
 
421
 
 
422
 AC_CONFIG_HEADERS([config.h])
 
423
@@ -1828,8 +1845,13 @@ src/lib-imap/Makefile
 
424
 src/lib-imap/Makefile
 
425
 src/lib-index/Makefile
 
426
 src/lib-mail/Makefile
 
427
+src/lib-managesieve/Makefile
 
428
 src/lib-ntlm/Makefile
 
429
 src/lib-settings/Makefile
 
430
+src/lib-sievestorage/Makefile
 
431
+src/lib-sieve/Makefile
 
432
+src/lib-sieve/cmu/Makefile
 
433
+src/lib-sieve/cmu/libsieve/Makefile
 
434
 src/lib-storage/Makefile
 
435
 src/lib-storage/index/Makefile
 
436
 src/lib-storage/index/maildir/Makefile
 
437
@@ -1843,6 +1865,8 @@ src/imap/Makefile
 
438
 src/imap/Makefile
 
439
 src/imap-login/Makefile
 
440
 src/login-common/Makefile
 
441
+src/managesieve/Makefile
 
442
+src/managesieve-login/Makefile
 
443
 src/master/Makefile
 
444
 src/pop3/Makefile
 
445
 src/pop3-login/Makefile
 
446
diff -r 894f003d9f5f dovecot-example.conf
 
447
--- a/dovecot-example.conf      Sun Mar 09 12:50:11 2008 +0200
 
448
+++ b/dovecot-example.conf      Sun May 04 16:00:59 2008 +0200
 
449
@@ -18,7 +18,7 @@
 
450
 # Base directory where to store runtime data.
 
451
 #base_dir = /var/run/dovecot/
 
452
 
 
453
-# Protocols we want to be serving: imap imaps pop3 pop3s
 
454
+# Protocols we want to be serving: imap imaps pop3 pop3s managesieve
 
455
 # If you only want to use dovecot-auth, you can set this to "none".
 
456
 #protocols = imap imaps
 
457
 
 
458
@@ -28,8 +28,8 @@
 
459
 # interfaces depending on the operating system.
 
460
 #
 
461
 # If you want to specify ports for each service, you will need to configure
 
462
-# these settings inside the protocol imap/pop3 { ... } section, so you can
 
463
-# specify different ports for IMAP/POP3. For example:
 
464
+# these settings inside the protocol imap/pop3/managesieve { ... } section, 
 
465
+# so you can specify different ports for IMAP/POP3/MANAGESIEVE. For example:
 
466
 #   protocol imap {
 
467
 #     listen = *:10143
 
468
 #     ssl_listen = *:10943
 
469
@@ -37,6 +37,10 @@
 
470
 #   }
 
471
 #   protocol pop3 {
 
472
 #     listen = *:10100
 
473
+#     ..
 
474
+#   }
 
475
+#   protocol managesieve {
 
476
+#     listen = *:12000
 
477
 #     ..
 
478
 #   }
 
479
 #listen = *
 
480
@@ -646,6 +650,48 @@ protocol pop3 {
 
481
   #     missing. This option simply sends it if it's missing.
 
482
   # The list is space-separated.
 
483
   #pop3_client_workarounds = 
 
484
+}
 
485
+
 
486
+##
 
487
+## MANAGESIEVE specific settings
 
488
+##
 
489
+
 
490
+protocol managesieve {
 
491
+  # Login executable location.
 
492
+  #login_executable = /usr/libexec/dovecot/managesieve-login
 
493
+
 
494
+  # MANAGESIEVE executable location. See IMAP's mail_executable above for 
 
495
+  # examples how this could be changed.
 
496
+  #mail_executable = /usr/libexec/dovecot/managesieve
 
497
+
 
498
+  # Maximum MANAGESIEVE command line length in bytes. This setting is 
 
499
+  # directly borrowed from IMAP. But, since long command lines are very
 
500
+  # unlikely with MANAGESIEVE, changing this will not be very useful.  
 
501
+  #managesieve_max_line_length = 65536
 
502
+
 
503
+  # Specifies the location of the symlink pointing to the active script in
 
504
+  # the sieve storage directory. This must match the SIEVE setting used by
 
505
+  # deliver (refer to http://wiki.dovecot.org/LDA/Sieve#location for more
 
506
+  # info). Variable substitution with % is recognized.
 
507
+  sieve=~/.dovecot.sieve
 
508
+
 
509
+  # This specifies the path to the directory where the uploaded scripts must
 
510
+  # be stored. In terms of '%' variable substitution it is identical to
 
511
+  # dovecot's mail_location setting used by the mail protocol daemons.
 
512
+  sieve_storage=~/sieve
 
513
+
 
514
+  # If, for some inobvious reason, the sieve_storage remains unset, the 
 
515
+  # managesieve daemon uses the specification of the mail_location to find out 
 
516
+  # where to store the sieve files (see explaination in README.managesieve). 
 
517
+  # The example below, when uncommented, overrides any global mail_location 
 
518
+  # specification and stores all the scripts in '~/mail/sieve' if sieve_storage 
 
519
+  # is unset. However, you should always use the sieve_storage setting.
 
520
+  # mail_location = mbox:~/mail
 
521
+
 
522
+  # To fool managesieve clients that are focused on timesieved you can
 
523
+  # specify the IMPLEMENTATION capability that the dovecot reports to clients 
 
524
+  # (default: dovecot).
 
525
+  #managesieve_implementation_string = Cyrus timsieved v2.2.13
 
526
 }
 
527
 
 
528
 ##
 
529
diff -r 894f003d9f5f src/Makefile.am
 
530
--- a/src/Makefile.am   Sun Mar 09 12:50:11 2008 +0200
 
531
+++ b/src/Makefile.am   Sun May 04 16:00:59 2008 +0200
 
532
@@ -4,6 +4,10 @@ endif
 
533
 
 
534
 if BUILD_DELIVER
 
535
 DELIVER = deliver
 
536
+endif
 
537
+
 
538
+if BUILD_MANAGESIEVE
 
539
+MANAGESIEVE = lib-managesieve lib-sievestorage lib-sieve managesieve managesieve-login 
 
540
 endif
 
541
 
 
542
 SUBDIRS = \
 
543
@@ -26,5 +30,6 @@ SUBDIRS = \
 
544
        imap \
 
545
        $(POP3D) \
 
546
        $(DELIVER) \
 
547
+       $(MANAGESIEVE) \
 
548
        util \
 
549
        plugins
 
550
diff -r 894f003d9f5f src/lib-managesieve/Makefile.am
 
551
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
552
+++ b/src/lib-managesieve/Makefile.am   Sun May 04 16:00:59 2008 +0200
 
553
@@ -0,0 +1,14 @@
 
554
+noinst_LIBRARIES = libmanagesieve.a
 
555
+
 
556
+AM_CPPFLAGS = \
 
557
+       -I$(top_srcdir)/src/lib \
 
558
+       -I$(top_srcdir)/src/lib-charset \
 
559
+       -I$(top_srcdir)/src/lib-mail
 
560
+
 
561
+libmanagesieve_a_SOURCES = \
 
562
+       managesieve-quote.c \
 
563
+       managesieve-parser.c 
 
564
+
 
565
+noinst_HEADERS = \
 
566
+       managesieve-quote.h \
 
567
+       managesieve-parser.h 
 
568
diff -r 894f003d9f5f src/lib-managesieve/managesieve-parser.c
 
569
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
570
+++ b/src/lib-managesieve/managesieve-parser.c  Sun May 04 16:00:59 2008 +0200
 
571
@@ -0,0 +1,672 @@
 
572
+#include "lib.h"
 
573
+#include "istream.h"
 
574
+#include "ostream.h"
 
575
+#include "strescape.h"
 
576
+#include "managesieve-parser.h"
 
577
+
 
578
+#define is_linebreak(c) \
 
579
+       ((c) == '\r' || (c) == '\n')
 
580
+
 
581
+#define LIST_ALLOC_SIZE 7
 
582
+
 
583
+enum arg_parse_type {
 
584
+       ARG_PARSE_NONE = 0,
 
585
+       ARG_PARSE_ATOM,
 
586
+       ARG_PARSE_STRING,
 
587
+       ARG_PARSE_LITERAL,
 
588
+       ARG_PARSE_LITERAL_DATA
 
589
+};
 
590
+
 
591
+struct managesieve_parser {
 
592
+       /* permanent */
 
593
+       pool_t pool;
 
594
+       struct istream *input;
 
595
+       struct ostream *output;
 
596
+       size_t max_line_size;
 
597
+       enum managesieve_parser_flags flags;
 
598
+
 
599
+       /* reset by managesieve_parser_reset(): */
 
600
+       size_t line_size;
 
601
+       struct managesieve_arg_list *root_list;
 
602
+       struct managesieve_arg_list *cur_list;
 
603
+
 
604
+       enum arg_parse_type cur_type;
 
605
+       size_t cur_pos; /* parser position in input buffer */
 
606
+
 
607
+       int str_first_escape; /* ARG_PARSE_STRING: index to first '\' */
 
608
+       uoff_t literal_size; /* ARG_PARSE_LITERAL: string size */
 
609
+
 
610
+       const char *error;
 
611
+
 
612
+       unsigned int literal_skip_crlf:1;
 
613
+       unsigned int literal_nonsync:1;
 
614
+       unsigned int eol:1;
 
615
+       unsigned int fatal_error:1;
 
616
+};
 
617
+
 
618
+/* @UNSAFE */
 
619
+#define LIST_REALLOC(parser, old_list, new_size) \
 
620
+       p_realloc((parser)->pool, old_list, \
 
621
+                 sizeof(struct managesieve_arg_list) + \
 
622
+                 (old_list == NULL ? 0 : \
 
623
+                  sizeof(struct managesieve_arg_list) * (old_list)->alloc), \
 
624
+                 sizeof(struct managesieve_arg_list) * (new_size))
 
625
+
 
626
+static void managesieve_args_realloc(struct managesieve_parser *parser, size_t size)
 
627
+{
 
628
+       parser->cur_list = LIST_REALLOC(parser, parser->cur_list, size);
 
629
+       parser->cur_list->alloc = size;
 
630
+
 
631
+  parser->root_list = parser->cur_list;
 
632
+}
 
633
+
 
634
+struct managesieve_parser *
 
635
+managesieve_parser_create(struct istream *input, struct ostream *output,
 
636
+                  size_t max_line_size)
 
637
+{
 
638
+       struct managesieve_parser *parser;
 
639
+
 
640
+       parser = i_new(struct managesieve_parser, 1);
 
641
+        parser->pool = pool_alloconly_create("MANAGESIEVE parser", 8192);
 
642
+       parser->input = input;
 
643
+       parser->output = output;
 
644
+       parser->max_line_size = max_line_size;
 
645
+
 
646
+       managesieve_args_realloc(parser, LIST_ALLOC_SIZE);
 
647
+       return parser;
 
648
+}
 
649
+
 
650
+void managesieve_parser_destroy(struct managesieve_parser **parser)
 
651
+{
 
652
+       pool_unref((*parser)->pool);
 
653
+       i_free(*parser);
 
654
+       *parser = NULL;
 
655
+}
 
656
+
 
657
+void managesieve_parser_reset(struct managesieve_parser *parser)
 
658
+{
 
659
+       p_clear(parser->pool);
 
660
+
 
661
+       parser->line_size = 0;
 
662
+
 
663
+       parser->root_list = NULL;
 
664
+       parser->cur_list = NULL;
 
665
+
 
666
+       parser->cur_type = ARG_PARSE_NONE;
 
667
+       parser->cur_pos = 0;
 
668
+
 
669
+       parser->str_first_escape = 0;
 
670
+       parser->literal_size = 0;
 
671
+
 
672
+       parser->error = NULL;
 
673
+
 
674
+       parser->literal_skip_crlf = FALSE;
 
675
+       parser->eol = FALSE;
 
676
+
 
677
+       managesieve_args_realloc(parser, LIST_ALLOC_SIZE);
 
678
+}
 
679
+
 
680
+const char *managesieve_parser_get_error(struct managesieve_parser *parser, bool *fatal)
 
681
+{
 
682
+       *fatal = parser->fatal_error;
 
683
+       return parser->error;
 
684
+}
 
685
+
 
686
+/* skip over everything parsed so far, plus the following whitespace */
 
687
+static int managesieve_parser_skip_to_next(struct managesieve_parser *parser,
 
688
+                                   const unsigned char **data,
 
689
+                                   size_t *data_size)
 
690
+{
 
691
+       size_t i;
 
692
+
 
693
+       for (i = parser->cur_pos; i < *data_size; i++) {
 
694
+               if ((*data)[i] != ' ')
 
695
+                       break;
 
696
+       }
 
697
+
 
698
+       parser->line_size += i;
 
699
+       i_stream_skip(parser->input, i);
 
700
+       parser->cur_pos = 0;
 
701
+
 
702
+       *data += i;
 
703
+       *data_size -= i;
 
704
+       return *data_size > 0;
 
705
+}
 
706
+
 
707
+static struct managesieve_arg *managesieve_arg_create(struct managesieve_parser *parser)
 
708
+{
 
709
+       struct managesieve_arg *arg;
 
710
+
 
711
+       i_assert(parser->cur_list != NULL);
 
712
+
 
713
+       /* @UNSAFE */
 
714
+       if (parser->cur_list->size == parser->cur_list->alloc)
 
715
+               managesieve_args_realloc(parser, parser->cur_list->alloc * 2);
 
716
+
 
717
+       arg = &parser->cur_list->args[parser->cur_list->size];
 
718
+       parser->cur_list->size++;
 
719
+
 
720
+       return arg;
 
721
+}
 
722
+
 
723
+static void managesieve_parser_save_arg(struct managesieve_parser *parser,
 
724
+                                const unsigned char *data, size_t size)
 
725
+{
 
726
+       struct managesieve_arg *arg;
 
727
+
 
728
+       arg = managesieve_arg_create(parser);
 
729
+
 
730
+       switch (parser->cur_type) {
 
731
+       case ARG_PARSE_ATOM:
 
732
+               /* simply save the string */
 
733
+               arg->type = MANAGESIEVE_ARG_ATOM;
 
734
+               arg->_data.str = p_strndup(parser->pool, data, size);
 
735
+               break;
 
736
+       case ARG_PARSE_STRING:
 
737
+               /* data is quoted and may contain escapes. */
 
738
+               i_assert(size > 0);
 
739
+
 
740
+               arg->type = MANAGESIEVE_ARG_STRING;
 
741
+               arg->_data.str = p_strndup(parser->pool, data+1, size-1);
 
742
+
 
743
+               /* remove the escapes */
 
744
+               if (parser->str_first_escape >= 0 &&
 
745
+                   (parser->flags & MANAGESIEVE_PARSE_FLAG_NO_UNESCAPE) == 0) {
 
746
+                       /* -1 because we skipped the '"' prefix */
 
747
+                       str_unescape(arg->_data.str +
 
748
+                                    parser->str_first_escape-1);
 
749
+               }
 
750
+               break;
 
751
+       case ARG_PARSE_LITERAL_DATA:
 
752
+               if ((parser->flags & MANAGESIEVE_PARSE_FLAG_LITERAL_SIZE) != 0) {
 
753
+                       /* save literal size */
 
754
+                       arg->type = MANAGESIEVE_ARG_LITERAL_SIZE;
 
755
+                       arg->_data.literal_size = parser->literal_size;
 
756
+               } else if ((parser->flags &
 
757
+                           MANAGESIEVE_PARSE_FLAG_LITERAL_TYPE) != 0) {
 
758
+                       arg->type = MANAGESIEVE_ARG_LITERAL;
 
759
+                       arg->_data.str = p_strndup(parser->pool, data, size);
 
760
+               } else {
 
761
+                       arg->type = MANAGESIEVE_ARG_STRING;
 
762
+                       arg->_data.str = p_strndup(parser->pool, data, size);
 
763
+               }
 
764
+               break;
 
765
+       default:
 
766
+               i_unreached();
 
767
+       }
 
768
+
 
769
+       parser->cur_type = ARG_PARSE_NONE;
 
770
+}
 
771
+
 
772
+static int is_valid_atom_char(struct managesieve_parser *parser, char chr)
 
773
+{
 
774
+       if (IS_ATOM_SPECIAL((unsigned char)chr)) {
 
775
+               parser->error = "Invalid characters in atom";
 
776
+               return FALSE;
 
777
+       } else if ((chr & 0x80) != 0) {
 
778
+               parser->error = "8bit data in atom";
 
779
+               return FALSE;
 
780
+       }
 
781
+
 
782
+       return TRUE;
 
783
+}
 
784
+
 
785
+static int managesieve_parser_read_atom(struct managesieve_parser *parser,
 
786
+                                const unsigned char *data, size_t data_size)
 
787
+{
 
788
+       size_t i;
 
789
+
 
790
+       /* read until we've found space, CR or LF. */
 
791
+       for (i = parser->cur_pos; i < data_size; i++) {
 
792
+               if (data[i] == ' ' || data[i] == ')' ||
 
793
+                        is_linebreak(data[i])) {
 
794
+                       managesieve_parser_save_arg(parser, data, i);
 
795
+                       break;
 
796
+               } else if (!is_valid_atom_char(parser, data[i]))
 
797
+                       return FALSE;
 
798
+       }
 
799
+
 
800
+       parser->cur_pos = i;
 
801
+       return parser->cur_type == ARG_PARSE_NONE;
 
802
+}
 
803
+
 
804
+static int managesieve_parser_read_string(struct managesieve_parser *parser,
 
805
+                                  const unsigned char *data, size_t data_size)
 
806
+{
 
807
+       size_t i;
 
808
+       int utf8_len;
 
809
+
 
810
+       /* QUOTED-CHAR        = SAFE-UTF8-CHAR / "\" QUOTED-SPECIALS
 
811
+        * quoted             = <"> *QUOTED-CHAR <">
 
812
+        *                    ;; limited to 1024 octets between the <">s
 
813
+        */
 
814
+
 
815
+       /* read until we've found non-escaped ", CR or LF */
 
816
+       for (i = parser->cur_pos; i < data_size; i++) {
 
817
+               if (data[i] == '"') {
 
818
+                       managesieve_parser_save_arg(parser, data, i);
 
819
+
 
820
+                       i++; /* skip the trailing '"' too */
 
821
+                       break;
 
822
+               }
 
823
+
 
824
+               if (data[i] == '\\') {
 
825
+                       if (i+1 == data_size) {
 
826
+                               /* known data ends with '\' - leave it to
 
827
+                                  next time as well if it happens to be \" */
 
828
+                               break;
 
829
+                       }
 
830
+
 
831
+                       /* save the first escaped char */
 
832
+                       if (parser->str_first_escape < 0)
 
833
+                               parser->str_first_escape = i;
 
834
+
 
835
+                       /* skip the escaped char */
 
836
+                       i++;
 
837
+
 
838
+                       if ( !IS_QUOTED_SPECIAL(data[i]) ) {
 
839
+                               parser->error = "Escaped quoted-string character is not a QUOTED-SPECIAL.";
 
840
+                               return FALSE;
 
841
+                       }
 
842
+
 
843
+                       continue;
 
844
+               }
 
845
+
 
846
+               /* Enforce valid UTF-8
 
847
+                */
 
848
+               if ( (utf8_len = UTF8_LEN(data[i])) == 0 ) {
 
849
+                       parser->error = "String contains invalid character.";
 
850
+                       return FALSE;
 
851
+               }
 
852
+               
 
853
+               if ( utf8_len > 1 ) {
 
854
+                       bool overlong = FALSE;
 
855
+
 
856
+                       if ( (i+utf8_len-1) >= data_size ) {
 
857
+                               /* Known data ends in the middle of a UTF-8 character;
 
858
+                                * leave it to next time.
 
859
+                                */
 
860
+                               break;
 
861
+                       }
 
862
+
 
863
+                       /* Check for overlong UTF-8 sequences */
 
864
+                       switch (utf8_len) {
 
865
+                       case 2:
 
866
+                               if (!(data[i] & 0x1E)) overlong = TRUE;
 
867
+                               break;
 
868
+                       case 3: 
 
869
+                               if (!(data[i] & 0x0F) && !(data[i+1] & 0x20)) overlong = TRUE;
 
870
+                               break;
 
871
+                       case 4:
 
872
+                               if (!(data[i] & 0x07) && !(data[i+1] & 0x30)) overlong = TRUE;                          
 
873
+                               break;
 
874
+                       case 5:
 
875
+                               if (!(data[i] & 0x03) && !(data[i+1] & 0x38)) overlong = TRUE;
 
876
+                               break;                          
 
877
+                       case 6:
 
878
+                               if (!(data[i] & 0x01) && !(data[i+1] & 0x3C)) overlong = TRUE;
 
879
+                               break;                          
 
880
+                       default:
 
881
+                               i_unreached();
 
882
+                       } 
 
883
+
 
884
+                       if ( overlong ) {
 
885
+                               parser->error = "String contains invalid/overlong UTF-8 character.";
 
886
+                               return FALSE;
 
887
+                       }
 
888
+
 
889
+                       i++;
 
890
+                       utf8_len--;
 
891
+       
 
892
+                       /* Parse the series of UTF8_1 characters */
 
893
+                       for (; utf8_len > 0; utf8_len--, i++ ) {  
 
894
+                               if (!IS_UTF8_1(data[i])) {
 
895
+                                       parser->error = "String contains invalid UTF-8 character.";
 
896
+                           return FALSE;
 
897
+                               }
 
898
+                       }
 
899
+               }
 
900
+       }
 
901
+
 
902
+       parser->cur_pos = i;
 
903
+       return parser->cur_type == ARG_PARSE_NONE;
 
904
+}
 
905
+
 
906
+static int managesieve_parser_literal_end(struct managesieve_parser *parser)
 
907
+{
 
908
+       if ((parser->flags & MANAGESIEVE_PARSE_FLAG_LITERAL_SIZE) == 0) {
 
909
+               if (parser->line_size >= parser->max_line_size ||
 
910
+                   parser->literal_size >
 
911
+                       parser->max_line_size - parser->line_size) {
 
912
+                       /* too long string, abort. */
 
913
+                       parser->error = "Literal size too large";
 
914
+                       parser->fatal_error = TRUE;
 
915
+                       return FALSE;
 
916
+               }
 
917
+       }
 
918
+
 
919
+       parser->cur_type = ARG_PARSE_LITERAL_DATA;
 
920
+       parser->literal_skip_crlf = TRUE;
 
921
+
 
922
+       parser->cur_pos = 0;
 
923
+       return TRUE;
 
924
+}
 
925
+
 
926
+static int managesieve_parser_read_literal(struct managesieve_parser *parser,
 
927
+                                   const unsigned char *data,
 
928
+                                   size_t data_size)
 
929
+{
 
930
+       size_t i, prev_size;
 
931
+
 
932
+       /* expecting digits + "}" */
 
933
+       for (i = parser->cur_pos; i < data_size; i++) {
 
934
+               if (data[i] == '}') {
 
935
+                       parser->line_size += i+1;
 
936
+                       i_stream_skip(parser->input, i+1);
 
937
+
 
938
+                       return managesieve_parser_literal_end(parser);
 
939
+               }
 
940
+
 
941
+               if (parser->literal_nonsync) {
 
942
+                       parser->error = "Expecting '}' after '+'";
 
943
+                       return FALSE;
 
944
+               }
 
945
+
 
946
+               if (data[i] == '+') {
 
947
+                       parser->literal_nonsync = TRUE;
 
948
+                       continue;
 
949
+               }
 
950
+
 
951
+               if (data[i] < '0' || data[i] > '9') {
 
952
+                       parser->error = "Invalid literal size";
 
953
+                       return FALSE;
 
954
+               }
 
955
+
 
956
+               prev_size = parser->literal_size;
 
957
+               parser->literal_size = parser->literal_size*10 + (data[i]-'0');
 
958
+
 
959
+               if (parser->literal_size < prev_size) {
 
960
+                       /* wrapped around, abort. */
 
961
+                       parser->error = "Literal size too large";
 
962
+                       return FALSE;
 
963
+               }
 
964
+       }
 
965
+
 
966
+       parser->cur_pos = i;
 
967
+       return FALSE;
 
968
+}
 
969
+
 
970
+static int managesieve_parser_read_literal_data(struct managesieve_parser *parser,
 
971
+                                        const unsigned char *data,
 
972
+                                        size_t data_size)
 
973
+{
 
974
+       if (parser->literal_skip_crlf) {
 
975
+
 
976
+               /* skip \r\n or \n, anything else gives an error */
 
977
+               if (data_size == 0)
 
978
+                       return FALSE;
 
979
+
 
980
+               if (*data == '\r') {
 
981
+                       parser->line_size++;
 
982
+                       data++; data_size--;
 
983
+                       i_stream_skip(parser->input, 1);
 
984
+
 
985
+                       if (data_size == 0)
 
986
+                               return FALSE;
 
987
+               }
 
988
+
 
989
+               if (*data != '\n') {
 
990
+                       parser->error = "Missing LF after literal size";
 
991
+                       return FALSE;
 
992
+               }
 
993
+
 
994
+               parser->line_size++;
 
995
+               data++; data_size--;
 
996
+               i_stream_skip(parser->input, 1);
 
997
+
 
998
+               parser->literal_skip_crlf = FALSE;
 
999
+
 
1000
+               i_assert(parser->cur_pos == 0);
 
1001
+       }
 
1002
+
 
1003
+       if ((parser->flags & MANAGESIEVE_PARSE_FLAG_LITERAL_SIZE) == 0) {
 
1004
+               /* now we just wait until we've read enough data */
 
1005
+               if (data_size < parser->literal_size) {
 
1006
+                       return FALSE;
 
1007
+               } else {
 
1008
+                       managesieve_parser_save_arg(parser, data,
 
1009
+                                            (size_t)parser->literal_size);
 
1010
+                       parser->cur_pos = (size_t)parser->literal_size;
 
1011
+                       return TRUE;
 
1012
+               }
 
1013
+       } else {
 
1014
+               /* we want to save only literal size, not the literal itself. */
 
1015
+               parser->eol = TRUE;
 
1016
+               managesieve_parser_save_arg(parser, NULL, 0);
 
1017
+               return TRUE;
 
1018
+       }
 
1019
+}
 
1020
+
 
1021
+/* Returns TRUE if argument was fully processed. Also returns TRUE if
 
1022
+   an argument inside a list was processed. */
 
1023
+static int managesieve_parser_read_arg(struct managesieve_parser *parser)
 
1024
+{
 
1025
+       const unsigned char *data;
 
1026
+       size_t data_size;
 
1027
+
 
1028
+       data = i_stream_get_data(parser->input, &data_size);
 
1029
+       if (data_size == 0)
 
1030
+               return FALSE;
 
1031
+
 
1032
+       while (parser->cur_type == ARG_PARSE_NONE) {
 
1033
+               /* we haven't started parsing yet */
 
1034
+               if (!managesieve_parser_skip_to_next(parser, &data, &data_size))
 
1035
+                       return FALSE;
 
1036
+               i_assert(parser->cur_pos == 0);
 
1037
+
 
1038
+               switch (data[0]) {
 
1039
+               case '\r':
 
1040
+               case '\n':
 
1041
+                       /* unexpected end of line */
 
1042
+                       parser->eol = TRUE;
 
1043
+                       return FALSE;
 
1044
+               case '"':
 
1045
+                       parser->cur_type = ARG_PARSE_STRING;
 
1046
+                       parser->str_first_escape = -1;
 
1047
+                       break;
 
1048
+               case '{':
 
1049
+                       parser->cur_type = ARG_PARSE_LITERAL;
 
1050
+                       parser->literal_size = 0;
 
1051
+                       parser->literal_nonsync = FALSE;
 
1052
+                       break;
 
1053
+               default:
 
1054
+                       if (!is_valid_atom_char(parser, data[0]))
 
1055
+                               return FALSE;
 
1056
+                       parser->cur_type = ARG_PARSE_ATOM;
 
1057
+                       break;
 
1058
+               }
 
1059
+
 
1060
+               parser->cur_pos++;
 
1061
+       }
 
1062
+
 
1063
+       i_assert(data_size > 0);
 
1064
+
 
1065
+       switch (parser->cur_type) {
 
1066
+       case ARG_PARSE_ATOM:
 
1067
+               if (!managesieve_parser_read_atom(parser, data, data_size))
 
1068
+                       return FALSE;
 
1069
+               break;
 
1070
+       case ARG_PARSE_STRING:
 
1071
+               if (!managesieve_parser_read_string(parser, data, data_size))
 
1072
+                       return FALSE;
 
1073
+               break;
 
1074
+       case ARG_PARSE_LITERAL:
 
1075
+               if (!managesieve_parser_read_literal(parser, data, data_size))
 
1076
+                       return FALSE;
 
1077
+
 
1078
+               /* pass through to parsing data. since input->skip was
 
1079
+                  modified, we need to get the data start position again. */
 
1080
+               data = i_stream_get_data(parser->input, &data_size);
 
1081
+
 
1082
+               /* fall through */
 
1083
+       case ARG_PARSE_LITERAL_DATA:
 
1084
+               if (!managesieve_parser_read_literal_data(parser, data, data_size))
 
1085
+                       return FALSE;
 
1086
+               break;
 
1087
+       default:
 
1088
+               i_unreached();
 
1089
+       }
 
1090
+
 
1091
+       i_assert(parser->cur_type == ARG_PARSE_NONE);
 
1092
+       return TRUE;
 
1093
+}
 
1094
+
 
1095
+/* ARG_PARSE_NONE checks that last argument isn't only partially parsed. */
 
1096
+#define IS_UNFINISHED(parser) \
 
1097
+        ((parser)->cur_type != ARG_PARSE_NONE || \
 
1098
+        (parser)->cur_list != parser->root_list)
 
1099
+
 
1100
+static int finish_line(struct managesieve_parser *parser, unsigned int count,
 
1101
+                      struct managesieve_arg **args)
 
1102
+{
 
1103
+       parser->line_size += parser->cur_pos;
 
1104
+       i_stream_skip(parser->input, parser->cur_pos);
 
1105
+       parser->cur_pos = 0;
 
1106
+
 
1107
+       if (count >= parser->root_list->alloc) {
 
1108
+               /* unused arguments must be NIL-filled. */
 
1109
+               parser->root_list =
 
1110
+                       LIST_REALLOC(parser, parser->root_list, count+1);
 
1111
+               parser->root_list->alloc = count+1;
 
1112
+       }
 
1113
+
 
1114
+       parser->root_list->args[parser->root_list->size].type = MANAGESIEVE_ARG_EOL;
 
1115
+
 
1116
+       *args = parser->root_list->args;
 
1117
+       return parser->root_list->size;
 
1118
+}
 
1119
+
 
1120
+int managesieve_parser_read_args(struct managesieve_parser *parser, unsigned int count,
 
1121
+                         enum managesieve_parser_flags flags, struct managesieve_arg **args)
 
1122
+{
 
1123
+       parser->flags = flags;
 
1124
+
 
1125
+       while (!parser->eol && (count == 0 || parser->root_list->size < count ||
 
1126
+                               IS_UNFINISHED(parser))) {
 
1127
+               if (!managesieve_parser_read_arg(parser))
 
1128
+                       break;
 
1129
+
 
1130
+               if (parser->line_size > parser->max_line_size) {
 
1131
+                       parser->error = "MANAGESIEVE command line too large";
 
1132
+                       break;
 
1133
+               }
 
1134
+       }
 
1135
+
 
1136
+       if (parser->error != NULL) {
 
1137
+               /* error, abort */
 
1138
+               parser->line_size += parser->cur_pos;
 
1139
+               i_stream_skip(parser->input, parser->cur_pos);
 
1140
+               parser->cur_pos = 0;
 
1141
+               *args = NULL;
 
1142
+               return -1;
 
1143
+       } else if ((!IS_UNFINISHED(parser) && count > 0 &&
 
1144
+                   parser->root_list->size >= count) || parser->eol) {
 
1145
+               /* all arguments read / end of line. */
 
1146
+                return finish_line(parser, count, args);
 
1147
+       } else {
 
1148
+               /* need more data */
 
1149
+               *args = NULL;
 
1150
+               return -2;
 
1151
+       }
 
1152
+}
 
1153
+
 
1154
+int managesieve_parser_finish_line(struct managesieve_parser *parser, unsigned int count,
 
1155
+                           enum managesieve_parser_flags flags,
 
1156
+                           struct managesieve_arg **args)
 
1157
+{
 
1158
+       const unsigned char *data;
 
1159
+       size_t data_size;
 
1160
+       int ret;
 
1161
+
 
1162
+       ret = managesieve_parser_read_args(parser, count, flags, args);
 
1163
+       if (ret == -2) {
 
1164
+               /* we should have noticed end of everything except atom */
 
1165
+               if (parser->cur_type == ARG_PARSE_ATOM) {
 
1166
+                       data = i_stream_get_data(parser->input, &data_size);
 
1167
+                       managesieve_parser_save_arg(parser, data, data_size);
 
1168
+               }
 
1169
+       }
 
1170
+       return finish_line(parser, count, args);
 
1171
+}
 
1172
+
 
1173
+const char *managesieve_parser_read_word(struct managesieve_parser *parser)
 
1174
+{
 
1175
+       const unsigned char *data;
 
1176
+       size_t i, data_size;
 
1177
+
 
1178
+       data = i_stream_get_data(parser->input, &data_size);
 
1179
+
 
1180
+       for (i = 0; i < data_size; i++) {
 
1181
+               if (data[i] == ' ' || data[i] == '\r' || data[i] == '\n')
 
1182
+                       break;
 
1183
+       }
 
1184
+
 
1185
+       if (i < data_size) {
 
1186
+               data_size = i + (data[i] == ' ' ? 1 : 0);
 
1187
+               parser->line_size += data_size;
 
1188
+               i_stream_skip(parser->input, data_size);
 
1189
+               return p_strndup(parser->pool, data, i);
 
1190
+       } else {
 
1191
+               return NULL;
 
1192
+       }
 
1193
+}
 
1194
+
 
1195
+const char *managesieve_arg_string(struct managesieve_arg *arg)
 
1196
+{
 
1197
+       if (arg->type == MANAGESIEVE_ARG_STRING) 
 
1198
+               return arg->_data.str;
 
1199
+
 
1200
+       return NULL;
 
1201
+}
 
1202
+
 
1203
+int managesieve_arg_number
 
1204
+       (struct managesieve_arg *arg, uoff_t *number)
 
1205
+{
 
1206
+       int i = 0;
 
1207
+       const char *data;
 
1208
+
 
1209
+       *number = 0;
 
1210
+
 
1211
+       if (arg->type == MANAGESIEVE_ARG_ATOM) {
 
1212
+               data = arg->_data.str;
 
1213
+               while (data[i] != '\0') {
 
1214
+                       if (data[i] < '0' || data[i] > '9')
 
1215
+                               return -1;
 
1216
+       
 
1217
+                       *number = (*number)*10 + (data[i] -'0');
 
1218
+                       i++;
 
1219
+               }
 
1220
+    
 
1221
+               return 1;
 
1222
+       }
 
1223
+
 
1224
+       return -1;
 
1225
+}
 
1226
+
 
1227
+char *_managesieve_arg_str_error(const struct managesieve_arg *arg)
 
1228
+{
 
1229
+       i_panic("Tried to access managesieve_arg type %d as string", arg->type);
 
1230
+       return NULL;
 
1231
+}
 
1232
+
 
1233
+uoff_t _managesieve_arg_literal_size_error(const struct managesieve_arg *arg)
 
1234
+{
 
1235
+       i_panic("Tried to access managesieve_arg type %d as literal size", arg->type);
 
1236
+       return 0;
 
1237
+}
 
1238
+
 
1239
+struct managesieve_arg_list *_managesieve_arg_list_error(const struct managesieve_arg *arg)
 
1240
+{
 
1241
+       i_panic("Tried to access managesieve_arg type %d as list", arg->type);
 
1242
+       return NULL;
 
1243
+}
 
1244
diff -r 894f003d9f5f src/lib-managesieve/managesieve-parser.h
 
1245
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
1246
+++ b/src/lib-managesieve/managesieve-parser.h  Sun May 04 16:00:59 2008 +0200
 
1247
@@ -0,0 +1,189 @@
 
1248
+#ifndef __MANAGESIEVE_PARSER_H
 
1249
+#define __MANAGESIEVE_PARSER_H
 
1250
+
 
1251
+/*
 
1252
+ * QUOTED-SPECIALS    = <"> / "\"
 
1253
+ */
 
1254
+#define IS_QUOTED_SPECIAL(c) \
 
1255
+       ((c) == '"' || (c) == '\\')
 
1256
+
 
1257
+/* 
 
1258
+ * ATOM-SPECIALS      = "(" / ")" / "{" / SP / CTL / QUOTED-SPECIALS
 
1259
+ */
 
1260
+#define IS_ATOM_SPECIAL(c) \
 
1261
+       ((c) == '(' || (c) == ')' || (c) == '{' || \
 
1262
+        (c) <= 32 || (c) == 0x7f || \
 
1263
+        IS_QUOTED_SPECIAL(c)) 
 
1264
+
 
1265
+/* 
 
1266
+ * CHAR               = %x01-7F
 
1267
+ */
 
1268
+#define IS_CHAR(c) \
 
1269
+       (((c) & 0x80) == 0)
 
1270
+
 
1271
+/* 
 
1272
+ * TEXT-CHAR          = %x01-09 / %x0B-0C / %x0E-7F
 
1273
+ *                       ;; any CHAR except CR and LF
 
1274
+ */
 
1275
+#define IS_TEXT_CHAR(c) \
 
1276
+       (IS_CHAR(c) && (c) != '\r' && (c) != '\n')
 
1277
+
 
1278
+/*
 
1279
+ * SAFE-CHAR          = %x01-09 / %x0B-0C / %x0E-21 /
 
1280
+ *                      %x23-5B / %x5D-7F
 
1281
+ *                      ;; any TEXT-CHAR except QUOTED-SPECIALS
 
1282
+ */
 
1283
+#define IS_SAFE_CHAR(c) \
 
1284
+       (IS_TEXT_CHAR(c) && !IS_QUOTED_SPECIAL(c))
 
1285
+
 
1286
+/* UTF8-1             = %x80-BF
 
1287
+ */
 
1288
+#define IS_UTF8_1(c) \
 
1289
+       (((c) & 0xC0) == 0x80)
 
1290
+
 
1291
+/* UTF8-2             = %xC0-DF UTF8-1
 
1292
+ */
 
1293
+#define IS_UTF8_2S(c) \
 
1294
+  (((c) & 0xE0) == 0xC0)
 
1295
+
 
1296
+/* UTF8-3             = %xE0-EF 2UTF8-1
 
1297
+ */
 
1298
+#define IS_UTF8_3S(c) \
 
1299
+  (((c) & 0xF0) == 0xE0)
 
1300
+
 
1301
+/* UTF8-4             = %xF0-F7 3UTF8-1
 
1302
+ */
 
1303
+#define IS_UTF8_4S(c) \
 
1304
+  (((c) & 0xF8) == 0xF0)
 
1305
+
 
1306
+/* UTF8-5             = %xF8-FB 4UTF8-1
 
1307
+ */
 
1308
+#define IS_UTF8_5S(c) \
 
1309
+  (((c) & 0xFC) == 0xF8)
 
1310
+
 
1311
+/* UTF8-6             = %xFC-FD 5UTF8-1
 
1312
+ */
 
1313
+#define IS_UTF8_6S(c) \
 
1314
+  (((c) & 0xFE) == 0xFC)
 
1315
+
 
1316
+/* SAFE-UTF8-CHAR     = SAFE-CHAR / UTF8-2 / UTF8-3 / UTF8-4 /
 
1317
+ *                      UTF8-5 / UTF8-6
 
1318
+ */
 
1319
+#define UTF8_LEN(c) \
 
1320
+  ( IS_SAFE_CHAR(c) ? 1 : \
 
1321
+    IS_UTF8_2S(c) ? 2 : \
 
1322
+    IS_UTF8_3S(c) ? 3 : \
 
1323
+    IS_UTF8_4S(c) ? 4 : \
 
1324
+    IS_UTF8_5S(c) ? 5 : \
 
1325
+    IS_UTF8_6S(c) ? 6 : 0 )
 
1326
+
 
1327
+enum managesieve_parser_flags {
 
1328
+       /* Set this flag if you wish to read only size of literal argument
 
1329
+          and not convert literal into string. Useful when you need to deal
 
1330
+          with large literal sizes. The literal must be the last read
 
1331
+          parameter. */
 
1332
+       MANAGESIEVE_PARSE_FLAG_LITERAL_SIZE     = 0x01,
 
1333
+       /* Don't remove '\' chars from string arguments */
 
1334
+       MANAGESIEVE_PARSE_FLAG_NO_UNESCAPE      = 0x02,
 
1335
+       /* Return literals as MANAGESIEVE_ARG_LITERAL instead of MANAGESIEVE_ARG_STRING */
 
1336
+       MANAGESIEVE_PARSE_FLAG_LITERAL_TYPE     = 0x04
 
1337
+};
 
1338
+
 
1339
+enum managesieve_arg_type {
 
1340
+       MANAGESIEVE_ARG_ATOM = 0,
 
1341
+       MANAGESIEVE_ARG_STRING,
 
1342
+
 
1343
+       /* literals are returned as MANAGESIEVE_ARG_STRING by default */
 
1344
+       MANAGESIEVE_ARG_LITERAL,
 
1345
+       MANAGESIEVE_ARG_LITERAL_SIZE,
 
1346
+
 
1347
+       MANAGESIEVE_ARG_EOL /* end of argument list */
 
1348
+};
 
1349
+
 
1350
+struct managesieve_parser;
 
1351
+
 
1352
+struct managesieve_arg {
 
1353
+       enum managesieve_arg_type type;
 
1354
+
 
1355
+       union {
 
1356
+               char *str;
 
1357
+               uoff_t literal_size;
 
1358
+       } _data;
 
1359
+};
 
1360
+
 
1361
+#define MANAGESIEVE_ARG_STR(arg) \
 
1362
+       ((arg)->type == MANAGESIEVE_ARG_STRING || \
 
1363
+   (arg)->type == MANAGESIEVE_ARG_ATOM || \
 
1364
+        (arg)->type == MANAGESIEVE_ARG_LITERAL ? \
 
1365
+        (arg)->_data.str : _managesieve_arg_str_error(arg))
 
1366
+
 
1367
+#define MANAGESIEVE_ARG_LITERAL_SIZE(arg) \
 
1368
+       (((arg)->type == MANAGESIEVE_ARG_LITERAL_SIZE) ? \
 
1369
+        (arg)->_data.literal_size : _managesieve_arg_literal_size_error(arg))
 
1370
+
 
1371
+struct managesieve_arg_list {
 
1372
+       size_t size, alloc;
 
1373
+       struct managesieve_arg args[1]; /* variable size */
 
1374
+};
 
1375
+
 
1376
+
 
1377
+/* Create new MANAGESIEVE argument parser. output is used for sending command
 
1378
+   continuation requests for literals.
 
1379
+
 
1380
+   max_line_size can be used to approximately limit the maximum amount of
 
1381
+   memory that gets allocated when parsing a line. Input buffer size limits
 
1382
+   the maximum size of each parsed token.
 
1383
+
 
1384
+   Usually the largest lines are large only because they have a one huge
 
1385
+   message set token, so you'll probably want to keep input buffer size the
 
1386
+   same as max_line_size. That means the maximum memory usage is around
 
1387
+   2 * max_line_size. */
 
1388
+struct managesieve_parser *
 
1389
+managesieve_parser_create(struct istream *input, struct ostream *output,
 
1390
+                  size_t max_line_size);
 
1391
+void managesieve_parser_destroy(struct managesieve_parser **parser);
 
1392
+
 
1393
+/* Reset the parser to initial state. */
 
1394
+void managesieve_parser_reset(struct managesieve_parser *parser);
 
1395
+
 
1396
+/* Return the last error in parser. fatal is set to TRUE if there's no way to
 
1397
+   continue parsing, currently only if too large non-sync literal size was
 
1398
+   given. */
 
1399
+const char *managesieve_parser_get_error(struct managesieve_parser *parser, bool *fatal);
 
1400
+
 
1401
+/* Read a number of arguments. This function doesn't call i_stream_read(), you
 
1402
+   need to do that. Returns number of arguments read (may be less than count
 
1403
+   in case of EOL), -2 if more data is needed or -1 if error occurred.
 
1404
+
 
1405
+   count-sized array of arguments are stored into args when return value is
 
1406
+   0 or larger. If all arguments weren't read, they're set to NIL. count
 
1407
+   can be set to 0 to read all arguments in the line. Last element in
 
1408
+   args is always of type MANAGESIEVE_ARG_EOL. */
 
1409
+int managesieve_parser_read_args(struct managesieve_parser *parser, unsigned int count,
 
1410
+                         enum managesieve_parser_flags flags, struct managesieve_arg **args);
 
1411
+
 
1412
+/* just like managesieve_parser_read_args(), but assume \n at end of data in
 
1413
+   input stream. */
 
1414
+int managesieve_parser_finish_line(struct managesieve_parser *parser, unsigned int count,
 
1415
+                           enum managesieve_parser_flags flags,
 
1416
+                           struct managesieve_arg **args);
 
1417
+
 
1418
+/* Read one word - used for reading tag and command name.
 
1419
+   Returns NULL if more data is needed. */
 
1420
+const char *managesieve_parser_read_word(struct managesieve_parser *parser);
 
1421
+
 
1422
+/* Returns the managesieve argument as string. If it is no string this returns NULL */
 
1423
+const char *managesieve_arg_string(struct managesieve_arg *arg);
 
1424
+
 
1425
+/* Returns 1 if the argument is a number. If it is no number this returns -1.
 
1426
+ * The number itself is stored in *number.
 
1427
+ */
 
1428
+int managesieve_arg_number
 
1429
+  (struct managesieve_arg *arg, uoff_t *number);
 
1430
+
 
1431
+/* Error functions */
 
1432
+char *_managesieve_arg_str_error(const struct managesieve_arg *arg);
 
1433
+uoff_t _managesieve_arg_literal_size_error(const struct managesieve_arg *arg);
 
1434
+struct managesieve_arg_list *_managesieve_arg_list_error(const struct managesieve_arg *arg);
 
1435
+
 
1436
+#endif
 
1437
diff -r 894f003d9f5f src/lib-managesieve/managesieve-quote.c
 
1438
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
1439
+++ b/src/lib-managesieve/managesieve-quote.c   Sun May 04 16:00:59 2008 +0200
 
1440
@@ -0,0 +1,176 @@
 
1441
+#include "lib.h"
 
1442
+#include "str.h"
 
1443
+#include "managesieve-parser.h"
 
1444
+#include "managesieve-quote.h"
 
1445
+
 
1446
+/* Turn the value string into a valid MANAGESIEVE string or literal, no matter 
 
1447
+ * what. QUOTED-SPECIALS are escaped, but any invalid (UTF-8) character
 
1448
+ * is simply removed. Linebreak characters are not considered invalid, but
 
1449
+ * they do force the generation of a string literal.
 
1450
+ */
 
1451
+void managesieve_quote_append(string_t *str, const unsigned char *value,
 
1452
+                      size_t value_len, bool compress_lwsp)
 
1453
+{
 
1454
+       size_t i, extra = 0;
 
1455
+       bool 
 
1456
+               last_lwsp = TRUE, 
 
1457
+               literal = FALSE, 
 
1458
+               modify = FALSE,
 
1459
+               escape = FALSE;
 
1460
+       int utf8_len;
 
1461
+
 
1462
+       if (value == NULL) {
 
1463
+               str_append(str, "\"\"");
 
1464
+               return;
 
1465
+       }
 
1466
+
 
1467
+       if (value_len == (size_t)-1)
 
1468
+               value_len = strlen((const char *) value);
 
1469
+
 
1470
+       for (i = 0; i < value_len; i++) {
 
1471
+               switch (value[i]) {
 
1472
+               case ' ':
 
1473
+               case '\t':
 
1474
+                       if (last_lwsp && compress_lwsp) {
 
1475
+                               modify = TRUE;
 
1476
+                               extra++;
 
1477
+                       }
 
1478
+                       last_lwsp = TRUE;
 
1479
+                       break;
 
1480
+               case '"':
 
1481
+               case '\\':
 
1482
+                       escape = TRUE;
 
1483
+                       last_lwsp = FALSE;
 
1484
+                       break;
 
1485
+               case 13:
 
1486
+               case 10:
 
1487
+                       literal = TRUE;
 
1488
+                       last_lwsp = TRUE;
 
1489
+                       break;
 
1490
+               default:
 
1491
+                       /* Enforce valid UTF-8
 
1492
+                        */
 
1493
+                       if ( (utf8_len=UTF8_LEN(value[i])) == 0 ) {
 
1494
+                               modify = TRUE;
 
1495
+                               extra++;
 
1496
+                               break;
 
1497
+                       }
 
1498
+
 
1499
+                       if ( utf8_len > 1 ) {
 
1500
+                               int c = utf8_len - 1;
 
1501
+
 
1502
+                               if ( (i+utf8_len-1) >= value_len ) {
 
1503
+                                       /* Value ends in the middle of a UTF-8 character;
 
1504
+                                        * Kill the partial UTF-8 character
 
1505
+                                        */
 
1506
+                                       extra += i + utf8_len - value_len;
 
1507
+                                       modify = TRUE;
 
1508
+                                       break;          
 
1509
+                               }
 
1510
+
 
1511
+                               /* Parse the series of UTF8_1 characters */
 
1512
+                               for (i++; c > 0; c--, i++ ) {
 
1513
+                                       if (!IS_UTF8_1(value[i])) {
 
1514
+                                               extra += utf8_len - c;
 
1515
+                                               modify = TRUE;
 
1516
+                                               break;
 
1517
+                                       }
 
1518
+                               }
 
1519
+                       }
 
1520
+                       
 
1521
+                       last_lwsp = FALSE;
 
1522
+               }
 
1523
+       }
 
1524
+
 
1525
+       if (!literal) {
 
1526
+               /* no linebreak chars, return as (escaped) "string" */
 
1527
+               str_append_c(str, '"');
 
1528
+       } else {
 
1529
+               /* return as literal */
 
1530
+               str_printfa(str, "{%"PRIuSIZE_T"}\r\n", value_len - extra);
 
1531
+       }
 
1532
+
 
1533
+       if (!modify && (literal || !escape))
 
1534
+               str_append_n(str, value, value_len);
 
1535
+       else {
 
1536
+               last_lwsp = TRUE;
 
1537
+               for (i = 0; i < value_len; i++) {
 
1538
+                       switch (value[i]) {
 
1539
+                       case '"':
 
1540
+                       case '\\':
 
1541
+                               last_lwsp = FALSE;
 
1542
+                               if (!literal) 
 
1543
+                                       str_append_c(str, '\\');
 
1544
+                               str_append_c(str, value[i]);
 
1545
+                               break;
 
1546
+                       case ' ':
 
1547
+                       case '\t':
 
1548
+                               if (!last_lwsp || !compress_lwsp)
 
1549
+                                       str_append_c(str, ' ');
 
1550
+                               last_lwsp = TRUE;
 
1551
+                               break;
 
1552
+                       case 13:
 
1553
+                       case 10:
 
1554
+                               last_lwsp = TRUE;
 
1555
+                               str_append_c(str, value[i]);
 
1556
+                               break;
 
1557
+                       default:
 
1558
+                               /* Enforce valid UTF-8
 
1559
+                                */
 
1560
+                               if ( (utf8_len=UTF8_LEN(value[i])) == 0 ) 
 
1561
+                                       break;
 
1562
+      
 
1563
+                               if ( utf8_len > 1 ) {
 
1564
+                                       int c = utf8_len - 1;
 
1565
+                                       int j;
 
1566
+
 
1567
+                                       if ( (i+utf8_len-1) >= value_len ) {
 
1568
+                                               /* Value ends in the middle of a UTF-8 character;
 
1569
+                                                * Kill the partial character
 
1570
+                                                */
 
1571
+                                               i = value_len;
 
1572
+                                               break;
 
1573
+                                       }
 
1574
+
 
1575
+                                       /* Parse the series of UTF8_1 characters */
 
1576
+                                       for (j = i+1; c > 0; c--, j++ ) {
 
1577
+                                               if (!IS_UTF8_1(value[j])) {
 
1578
+                                                       /* Skip until after this erroneous character */
 
1579
+                                                       i = j;
 
1580
+                                                       break;
 
1581
+                                               }
 
1582
+                                       }
 
1583
+
 
1584
+                                       /* Append the UTF-8 character. Last octet is done later */
 
1585
+                                       c = utf8_len - 1;
 
1586
+                                       for (; c > 0; c--, i++ ) 
 
1587
+                                               str_append_c(str, value[i]);
 
1588
+                               }
 
1589
+     
 
1590
+                               last_lwsp = FALSE;
 
1591
+                               str_append_c(str, value[i]);
 
1592
+                               break;
 
1593
+                       }
 
1594
+               }
 
1595
+       }
 
1596
+
 
1597
+       if (!literal)
 
1598
+               str_append_c(str, '"');
 
1599
+}
 
1600
+
 
1601
+char *managesieve_quote(pool_t pool, const unsigned char *value, size_t value_len)
 
1602
+{
 
1603
+       string_t *str;
 
1604
+       char *ret;
 
1605
+
 
1606
+       if (value == NULL)
 
1607
+               return "\"\"";
 
1608
+
 
1609
+       t_push();
 
1610
+       str = t_str_new(value_len + MAX_INT_STRLEN + 5);
 
1611
+       managesieve_quote_append(str, value, value_len, TRUE);
 
1612
+       ret = p_strndup(pool, str_data(str), str_len(str));
 
1613
+       t_pop();
 
1614
+
 
1615
+       return ret;
 
1616
+}
 
1617
diff -r 894f003d9f5f src/lib-managesieve/managesieve-quote.h
 
1618
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
1619
+++ b/src/lib-managesieve/managesieve-quote.h   Sun May 04 16:00:59 2008 +0200
 
1620
@@ -0,0 +1,17 @@
 
1621
+#ifndef __IMAP_QUOTE_H
 
1622
+#define __IMAP_QUOTE_H
 
1623
+
 
1624
+/* Return value suitable for sending to client, either as quoted-string or
 
1625
+   literal. Note that this also converts TABs into spaces, multiple spaces
 
1626
+   into single space and NULs to #128. */
 
1627
+char *managesieve_quote(pool_t pool, const unsigned char *value, size_t value_len);
 
1628
+
 
1629
+/* Append to existing string. */
 
1630
+void managesieve_quote_append(string_t *str, const unsigned char *value,
 
1631
+                      size_t value_len, bool compress_lwsp);
 
1632
+
 
1633
+#define managesieve_quote_append_string(str, value, compress_lwsp) \
 
1634
+       managesieve_quote_append(str, (const unsigned char *)(value), \
 
1635
+                         (size_t)-1, compress_lwsp)
 
1636
+
 
1637
+#endif
 
1638
diff -r 894f003d9f5f src/lib-sieve/Makefile.am
 
1639
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
1640
+++ b/src/lib-sieve/Makefile.am Sun May 04 16:00:59 2008 +0200
 
1641
@@ -0,0 +1,20 @@
 
1642
+noinst_LTLIBRARIES = libsieve.la
 
1643
+
 
1644
+SUBDIRS = cmu
 
1645
+
 
1646
+INCLUDES = \
 
1647
+       -I$(top_srcdir)/src/lib \
 
1648
+       -I$(top_srcdir)/src/lib-storage \
 
1649
+       -I$(top_srcdir)/src/lib-mail \
 
1650
+       -I$(top_srcdir)/src/lib-sievestorage
 
1651
+
 
1652
+# FIXME: Make this configurable
 
1653
+libsieve_la_LIBADD = \
 
1654
+       cmu/libsieve_cmu.la
 
1655
+
 
1656
+libsieve_la_SOURCES = \
 
1657
+       sieve-implementation.c 
 
1658
+
 
1659
+noinst_HEADERS = \
 
1660
+       sieve-implementation.h \
 
1661
+       sieve-implementation-private.h
 
1662
diff -r 894f003d9f5f src/lib-sieve/cmu/Makefile.am
 
1663
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
1664
+++ b/src/lib-sieve/cmu/Makefile.am     Sun May 04 16:00:59 2008 +0200
 
1665
@@ -0,0 +1,24 @@
 
1666
+noinst_LTLIBRARIES = libsieve_cmu.la
 
1667
+
 
1668
+SUBDIRS = libsieve
 
1669
+
 
1670
+INCLUDES = \
 
1671
+       -I$(top_srcdir)/src/lib \
 
1672
+       -I$(top_srcdir)/src/lib-sieve \
 
1673
+       -I$(top_srcdir)/src/lib-sievestorage \
 
1674
+       -I$(top_srcdir)/src/lib-mail \
 
1675
+       -I$(top_srcdir)/src/lib-storage \
 
1676
+       -I$(top_srcdir)/src/deliver
 
1677
+
 
1678
+libsieve_cmu_la_LIBADD = libsieve/libsieve.la
 
1679
+
 
1680
+libsieve_cmu_la_SOURCES = \
 
1681
+       cmu-sieve.c \
 
1682
+       imparse.c \
 
1683
+       map.c 
 
1684
+       
 
1685
+noinst_HEADERS = \
 
1686
+    imparse.h \
 
1687
+    libconfig.h \
 
1688
+    map.h \
 
1689
+    xmalloc.h
 
1690
diff -r 894f003d9f5f src/lib-sieve/cmu/cmu-sieve.c
 
1691
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
1692
+++ b/src/lib-sieve/cmu/cmu-sieve.c     Sun May 04 16:00:59 2008 +0200
 
1693
@@ -0,0 +1,498 @@
 
1694
+
 
1695
+/* Copyright (C) 2005-2006 Timo Sirainen */
 
1696
+
 
1697
+#include "lib.h"
 
1698
+#include "ioloop.h"
 
1699
+#include "array.h"
 
1700
+#include "hostpid.h"
 
1701
+#include "str.h"
 
1702
+#include "str-sanitize.h"
 
1703
+#include "write-full.h"
 
1704
+#include "libsieve/sieve_interface.h"
 
1705
+#include "sieve-script.h"
 
1706
+#include "sieve-implementation-private.h"
 
1707
+
 
1708
+#include <fcntl.h>
 
1709
+#include <unistd.h>
 
1710
+#include <sys/stat.h>
 
1711
+#include <sys/wait.h>
 
1712
+
 
1713
+extern struct sieve_implementation cmu_sieve;
 
1714
+
 
1715
+struct et_list *_et_list = NULL;
 
1716
+
 
1717
+/* data per script */
 
1718
+typedef struct script_data {
 
1719
+       string_t *errors;
 
1720
+       int     num_errors;
 
1721
+} script_data_t;
 
1722
+
 
1723
+typedef struct {
 
1724
+       const char *id;
 
1725
+       void *context;
 
1726
+} sieve_msgdata_t;
 
1727
+
 
1728
+/* gets the header "head" from msg. */
 
1729
+static int getheader(void *v, const char *phead, const char ***body)
 
1730
+{
 
1731
+       sieve_msgdata_t *m = v;
 
1732
+
 
1733
+       if (phead==NULL) return SIEVE_FAIL;
 
1734
+       *body = (const char **)sieve_runenv_get_mail_headers(m->context, phead);
 
1735
+
 
1736
+       if (*body) {
 
1737
+               return SIEVE_OK;
 
1738
+       } else {
 
1739
+               return SIEVE_FAIL;
 
1740
+       }
 
1741
+}
 
1742
+
 
1743
+static int getsize(void *mc, int *size)
 
1744
+{
 
1745
+       sieve_msgdata_t *md = mc;
 
1746
+       uoff_t psize;
 
1747
+
 
1748
+       psize = sieve_runenv_get_mail_size(md->context);
 
1749
+       if (psize == (uoff_t)-1)
 
1750
+               return SIEVE_FAIL;
 
1751
+
 
1752
+       *size = psize;
 
1753
+       return SIEVE_OK;
 
1754
+}
 
1755
+
 
1756
+static int getenvelope(void *mc, const char *field, const char ***contents)
 
1757
+{
 
1758
+       array_t ARRAY_DEFINE(values, const char *);
 
1759
+       sieve_msgdata_t *m = (sieve_msgdata_t *) mc;
 
1760
+       const char *data;
 
1761
+
 
1762
+       // FIXME: Should prob. not put this on the default pool
 
1763
+       ARRAY_CREATE(&values, default_pool, const char *, 1);
 
1764
+
 
1765
+       if (!sieve_runenv_get_envelope(m->context, field, &values) ) {
 
1766
+               *contents = NULL;
 
1767
+               return SIEVE_FAIL;
 
1768
+       }
 
1769
+
 
1770
+       data = NULL;
 
1771
+       array_append(&values, &data, 1);
 
1772
+
 
1773
+       *contents = array_count(&values) == 1 ? NULL :
 
1774
+         array_get_modifyable(&values, NULL);
 
1775
+
 
1776
+       return *contents != NULL ? SIEVE_OK : SIEVE_FAIL;
 
1777
+}
 
1778
+
 
1779
+static int sieve_redirect(void *ac, 
 
1780
+                         void *ic __attr_unused__, 
 
1781
+                         void *sc __attr_unused__, void *mc, const char **errmsg)
 
1782
+{
 
1783
+       sieve_redirect_context_t *rc = (sieve_redirect_context_t *) ac;
 
1784
+       sieve_msgdata_t *m = mc;
 
1785
+       const char *dupeid;
 
1786
+       int res;
 
1787
+
 
1788
+       /* if we have a msgid, we can track our redirects */
 
1789
+       dupeid = m->id == NULL ? NULL : t_strdup_printf("%s-%s", m->id, rc->addr);
 
1790
+       if (dupeid != NULL) {
 
1791
+               /* ok, let's see if we've redirected this message before */
 
1792
+               if (sieve_runenv_is_duplicate(m->context, dupeid, strlen(dupeid))) {
 
1793
+                       /*duplicate_log(m->id, sd->username, "redirect");*/
 
1794
+                       i_info("discarded duplicate forward (%s -> %s)",
 
1795
+                               str_sanitize(m->id, 80), str_sanitize(rc->addr, 80));
 
1796
+                       return SIEVE_OK;
 
1797
+               }
 
1798
+       }
 
1799
+
 
1800
+       if ((res = sieve_runenv_send_forward(m->context, rc->addr)) == 0) {
 
1801
+               /* mark this message as redirected */
 
1802
+               i_info("forwarded id %s to <%s>",
 
1803
+                       m->id == NULL ? "" : str_sanitize(m->id, 80),
 
1804
+                       str_sanitize(rc->addr, 80));
 
1805
+               
 
1806
+               if (dupeid != NULL) {
 
1807
+                       sieve_runenv_mark_duplicate(m->context,dupeid, strlen(dupeid), 
 
1808
+                               DUPLICATE_DEFAULT_KEEP);
 
1809
+               }
 
1810
+               return SIEVE_OK;
 
1811
+       } 
 
1812
+
 
1813
+       *errmsg = "Error sending mail";
 
1814
+       return SIEVE_FAIL;
 
1815
+}
 
1816
+
 
1817
+static int sieve_discard(void *ac __attr_unused__, 
 
1818
+                        void *ic __attr_unused__, 
 
1819
+                        void *sc __attr_unused__, void *mc,
 
1820
+                        const char **errmsg __attr_unused__)
 
1821
+{
 
1822
+       sieve_msgdata_t *md = mc;
 
1823
+
 
1824
+       /* ok, we won't file it, but log it */
 
1825
+       i_info("discarded id %s", md->id == NULL ? "" : str_sanitize(md->id, 80));
 
1826
+       return SIEVE_OK;
 
1827
+}
 
1828
+
 
1829
+static int sieve_reject(void *ac, 
 
1830
+                       void *ic __attr_unused__, 
 
1831
+                       void *sc __attr_unused__, 
 
1832
+                       void *mc, const char **errmsg)
 
1833
+{
 
1834
+       sieve_reject_context_t *rc = (sieve_reject_context_t *) ac;
 
1835
+       sieve_msgdata_t *md = (sieve_msgdata_t *) mc;
 
1836
+       int res;
 
1837
+
 
1838
+       if ((res = sieve_runenv_send_rejection(md->context, rc->msg)) == 0) {
 
1839
+               i_info("rejected id %s",
 
1840
+                       md->id == NULL ? "" : str_sanitize(md->id, 80));
 
1841
+               return SIEVE_OK;
 
1842
+       } else {
 
1843
+               *errmsg = "Error sending mail";
 
1844
+               return SIEVE_FAIL;
 
1845
+  }
 
1846
+  return SIEVE_FAIL;
 
1847
+}
 
1848
+
 
1849
+static int sieve_fileinto(void *ac, 
 
1850
+                         void *ic __attr_unused__,
 
1851
+                         void *sc __attr_unused__, 
 
1852
+                         void *mc,
 
1853
+                         const char **errmsg __attr_unused__)
 
1854
+{
 
1855
+       sieve_fileinto_context_t *fc = (sieve_fileinto_context_t *) ac;
 
1856
+       sieve_msgdata_t *md = (sieve_msgdata_t *) mc;
 
1857
+
 
1858
+       if (sieve_runenv_mail_save
 
1859
+           (md->context, fc->mailbox, fc->imapflags->flag, 
 
1860
+            fc->imapflags->nflags) < 0)
 
1861
+               return SIEVE_FAIL;
 
1862
+
 
1863
+       i_info("saved mail to %s", fc->mailbox);
 
1864
+       return SIEVE_OK;
 
1865
+}
 
1866
+
 
1867
+static int sieve_keep(void *ac, 
 
1868
+       void *ic __attr_unused__,
 
1869
+       void *sc __attr_unused__, 
 
1870
+       void *mc, const char **errmsg __attr_unused__)
 
1871
+{
 
1872
+       sieve_keep_context_t *kc = (sieve_keep_context_t *) ac;
 
1873
+       sieve_msgdata_t *md = (sieve_msgdata_t *) mc;
 
1874
+
 
1875
+       if (sieve_runenv_mail_save
 
1876
+           (md->context, NULL, kc->imapflags->flag, 
 
1877
+            kc->imapflags->nflags) < 0)
 
1878
+               return SIEVE_FAIL;
 
1879
+
 
1880
+       return SIEVE_OK;
 
1881
+}
 
1882
+
 
1883
+static int sieve_notify(void *ac __attr_unused__,
 
1884
+                       void *interp_context __attr_unused__,
 
1885
+                       void *script_context __attr_unused__,
 
1886
+                       void *mc __attr_unused__,
 
1887
+                       const char **errmsg __attr_unused__)
 
1888
+{
 
1889
+       return SIEVE_FAIL;
 
1890
+}
 
1891
+
 
1892
+static int autorespond(void *ac, 
 
1893
+                      void *ic __attr_unused__,
 
1894
+                      void *sc __attr_unused__,
 
1895
+                      void *mc,
 
1896
+                      const char **errmsg __attr_unused__)
 
1897
+{
 
1898
+       sieve_autorespond_context_t *arc = (sieve_autorespond_context_t *) ac;
 
1899
+       sieve_msgdata_t *md = (sieve_msgdata_t *) mc;
 
1900
+       int ret;
 
1901
+
 
1902
+       /* ok, let's see if we've responded before */
 
1903
+       ret = sieve_runenv_is_duplicate(md->context, arc->hash, arc->len) ?
 
1904
+         SIEVE_DONE : SIEVE_OK;
 
1905
+
 
1906
+       if (ret == SIEVE_OK) {
 
1907
+               sieve_runenv_mark_duplicate(md->context, arc->hash, arc->len, 
 
1908
+                                           arc->days * (24 * 60 * 60));
 
1909
+       }
 
1910
+
 
1911
+       return ret;
 
1912
+}
 
1913
+
 
1914
+static int send_response(void *ac, 
 
1915
+       void *ic __attr_unused__, 
 
1916
+       void *sc __attr_unused__, 
 
1917
+       void *mc,
 
1918
+       const char **errmsg)
 
1919
+{
 
1920
+       sieve_send_response_context_t *src = (sieve_send_response_context_t *) ac;
 
1921
+       sieve_msgdata_t *md = mc;
 
1922
+       const char *outmsgid;
 
1923
+
 
1924
+       if (sieve_runenv_send_message
 
1925
+           (md->context, src->fromaddr, src->addr, 
 
1926
+            src->subj, src->mime, src->msg, &outmsgid) == 0) {
 
1927
+               sieve_runenv_mark_duplicate
 
1928
+                 (md->context, outmsgid, strlen(outmsgid),     DUPLICATE_DEFAULT_KEEP);
 
1929
+               return SIEVE_OK;
 
1930
+       } else {
 
1931
+               *errmsg = "Error sending mail";
 
1932
+               return SIEVE_FAIL;
 
1933
+       }
 
1934
+}
 
1935
+
 
1936
+/* vacation support */
 
1937
+sieve_vacation_t vacation = {
 
1938
+    1,                         /* min response */
 
1939
+    31,                                /* max response */
 
1940
+    &autorespond,              /* autorespond() */
 
1941
+    &send_response             /* send_response() */
 
1942
+};
 
1943
+
 
1944
+/* imapflags support */
 
1945
+static char *markflags[] = { "\\flagged" };
 
1946
+static sieve_imapflags_t mark = { markflags, 1 };
 
1947
+
 
1948
+static int sieve_parse_error_handler(int lineno, const char *msg, 
 
1949
+                                    void *ic __attr_unused__,
 
1950
+                                    void *sc)
 
1951
+{
 
1952
+       script_data_t *sd = (script_data_t *) sc;
 
1953
+
 
1954
+       if (sd->errors == NULL) 
 
1955
+               sd->errors = str_new(default_pool, 1024);
 
1956
+
 
1957
+       if (sd->num_errors == 1) 
 
1958
+               str_append(sd->errors, "\r\n");
 
1959
+    
 
1960
+       str_printfa(sd->errors, "line %d: %s", lineno, msg);
 
1961
+
 
1962
+       if (sd->num_errors >= 1) 
 
1963
+               str_append(sd->errors, "\r\n");
 
1964
+
 
1965
+       sd->num_errors++;
 
1966
+       return SIEVE_OK;
 
1967
+}
 
1968
+
 
1969
+static int sieve_execute_error_handler(const char *msg, 
 
1970
+                                      void *ic __attr_unused__,
 
1971
+                                      void *sc __attr_unused__,
 
1972
+                                      void *mc __attr_unused__)
 
1973
+{
 
1974
+       i_info("sieve runtime error: %s", msg);
 
1975
+       return SIEVE_OK;
 
1976
+}
 
1977
 
1978
+static sieve_interp_t *setup_sieve(void)
 
1979
+{
 
1980
+       sieve_interp_t *interp = NULL;
 
1981
+       int res;
 
1982
+
 
1983
+       res = sieve_interp_alloc(&interp, NULL);
 
1984
+       if (res != SIEVE_OK)
 
1985
+               i_fatal("sieve_interp_alloc() returns %d\n", res);
 
1986
+
 
1987
+       res = sieve_register_redirect(interp, &sieve_redirect);
 
1988
+       if (res != SIEVE_OK)
 
1989
+               i_fatal("sieve_register_redirect() returns %d\n", res);
 
1990
+       res = sieve_register_discard(interp, &sieve_discard);
 
1991
+       if (res != SIEVE_OK)
 
1992
+               i_fatal("sieve_register_discard() returns %d\n", res);
 
1993
+       res = sieve_register_reject(interp, &sieve_reject);
 
1994
+       if (res != SIEVE_OK)
 
1995
+               i_fatal("sieve_register_reject() returns %d\n", res);
 
1996
+       res = sieve_register_fileinto(interp, &sieve_fileinto);
 
1997
+       if (res != SIEVE_OK)
 
1998
+               i_fatal("sieve_register_fileinto() returns %d\n", res);
 
1999
+       res = sieve_register_keep(interp, &sieve_keep);
 
2000
+       if (res != SIEVE_OK)
 
2001
+               i_fatal("sieve_register_keep() returns %d\n", res);
 
2002
+       res = sieve_register_imapflags(interp, &mark);
 
2003
+       if (res != SIEVE_OK)
 
2004
+               i_fatal("sieve_register_imapflags() returns %d\n", res);
 
2005
+       res = sieve_register_notify(interp, &sieve_notify);
 
2006
+       if (res != SIEVE_OK)
 
2007
+               i_fatal("sieve_register_notify() returns %d\n", res);
 
2008
+       res = sieve_register_size(interp, &getsize);
 
2009
+       if (res != SIEVE_OK)
 
2010
+               i_fatal("sieve_register_size() returns %d\n", res);
 
2011
+       res = sieve_register_header(interp, &getheader);
 
2012
+       if (res != SIEVE_OK)
 
2013
+               i_fatal("sieve_register_header() returns %d\n", res);
 
2014
+       
 
2015
+       res = sieve_register_envelope(interp, &getenvelope);
 
2016
+       if (res != SIEVE_OK)
 
2017
+               i_fatal("sieve_register_envelope() returns %d\n", res);
 
2018
+       res = sieve_register_vacation(interp, &vacation);
 
2019
+       if (res != SIEVE_OK)
 
2020
+               i_fatal("sieve_register_vacation() returns %d\n", res);
 
2021
+       res = sieve_register_parse_error(interp, &sieve_parse_error_handler);
 
2022
+       if (res != SIEVE_OK)
 
2023
+               i_fatal("sieve_register_parse_error() returns %d\n", res);
 
2024
+       res = sieve_register_execute_error(interp,  &sieve_execute_error_handler);
 
2025
+       if (res != SIEVE_OK)
 
2026
+               i_fatal("sieve_register_execute_error() returns %d\n", res);
 
2027
+
 
2028
+       return interp;
 
2029
+}
 
2030
+
 
2031
+static int
 
2032
+_cmu_sieve_compile(sieve_interp_t *interp, script_data_t *sdata,
 
2033
+                    const char *script_path, const char *compiled_path)
 
2034
+{
 
2035
+       struct stat st, st2;
 
2036
+       sieve_script_t *script;
 
2037
+       bytecode_info_t *bc;
 
2038
+       const char *temp_path;
 
2039
+       FILE *f;
 
2040
+       int fd, ret;
 
2041
+
 
2042
+       if (stat(script_path, &st) < 0) {
 
2043
+               if (errno == ENOENT)
 
2044
+                       return 0;
 
2045
+               i_error("stat(%s) failed: %m", script_path);
 
2046
+               return -1;
 
2047
+       }
 
2048
+       if (compiled_path != NULL) {
 
2049
+               if (stat(compiled_path, &st2) < 0) {
 
2050
+                       if (errno != ENOENT) {
 
2051
+                               i_error("stat(%s) failed: %m", script_path);
 
2052
+                               return -1;
 
2053
+                       }
 
2054
+               } else {
 
2055
+                       if (st.st_mtime < st2.st_mtime)
 
2056
+                               return 1;
 
2057
+               }
 
2058
+       }
 
2059
+
 
2060
+       /* need to compile */
 
2061
+       f = fopen(script_path, "r");
 
2062
+       if (f == NULL) {
 
2063
+               i_error("fopen(%s) failed: %m", script_path);
 
2064
+               return -1;
 
2065
+       }
 
2066
+
 
2067
+       ret = sieve_script_parse(interp, f, sdata, &script);
 
2068
+       if (ret != SIEVE_OK) {
 
2069
+               if (sdata->errors == NULL)
 
2070
+                       sieve_set_error("parse error %d", ret);
 
2071
+               else
 
2072
+                       sieve_set_error("%s", str_c(sdata->errors));
 
2073
+               
 
2074
+               return -1;
 
2075
+       }
 
2076
+
 
2077
+       if (compiled_path != NULL) {
 
2078
+               if (sieve_generate_bytecode(&bc, script) < 0) {
 
2079
+                       i_error("sieve_generate_bytecode() failed");
 
2080
+                       return -1;
 
2081
+               }
 
2082
+
 
2083
+               /* write to temp file */
 
2084
+               temp_path = t_strconcat(compiled_path, ".tmp", NULL);
 
2085
+               fd = open(temp_path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
 
2086
+               if(fd == -1) {
 
2087
+                       i_error("open(%s) failed: %m", temp_path);
 
2088
+                       return -1;
 
2089
+               }
 
2090
+
 
2091
+               if (sieve_emit_bytecode(fd, bc) < 0) {
 
2092
+                       i_error("sieve_emit_bytecode() failed");
 
2093
+                       return -1;
 
2094
+               }
 
2095
+
 
2096
+               if (close(fd) < 0)
 
2097
+                       i_error("close() failed: %m");
 
2098
+
 
2099
+               /* and finally replace the script */
 
2100
+               if (rename(temp_path, compiled_path) < 0) {
 
2101
+                       i_error("rename(%s, %s) failed: %m", temp_path, compiled_path);
 
2102
+                       return -1;
 
2103
+               }
 
2104
+       }
 
2105
+
 
2106
+       return 1;
 
2107
+}
 
2108
+
 
2109
+static int cmu_sieve_compile
 
2110
+       (struct sieve_script *script, bool verify_only __attr_unused__)
 
2111
+{
 
2112
+       const char *script_path;
 
2113
+       sieve_interp_t *interp;
 
2114
+       script_data_t sdata;
 
2115
+       int ret;
 
2116
+       
 
2117
+       script_path = sieve_script_filename(script);
 
2118
+       
 
2119
+       if (script_path == NULL)
 
2120
+               return -1;
 
2121
+       
 
2122
+       interp = setup_sieve();
 
2123
+       
 
2124
+       memset(&sdata, 0, sizeof(sdata));
 
2125
+       
 
2126
+       ret = _cmu_sieve_compile(interp, &sdata, script_path, NULL);
 
2127
+       
 
2128
+       /* Let's not assume that an error string is created only when an error
 
2129
+        * occurs...better safe than sorry
 
2130
+        */
 
2131
+       if (sdata.errors != NULL)
 
2132
+               str_free(&sdata.errors);
 
2133
+
 
2134
+       return ret;
 
2135
+}
 
2136
+
 
2137
+static int cmu_sieve_run
 
2138
+       (struct sieve_script *script, void *context)
 
2139
+{
 
2140
+       const char *script_path;
 
2141
+       sieve_interp_t *interp;
 
2142
+       sieve_bytecode_t *bytecode;
 
2143
+       script_data_t sdata;
 
2144
+       sieve_msgdata_t mdata;
 
2145
+       const char *compiled_path, *path;
 
2146
+       int ret;
 
2147
+
 
2148
+       script_path = sieve_script_filename(script);
 
2149
+
 
2150
+       if (script_path == NULL)
 
2151
+               return -1;
 
2152
+
 
2153
+       interp = setup_sieve();
 
2154
+
 
2155
+       memset(&sdata, 0, sizeof(sdata));
 
2156
+
 
2157
+       compiled_path = t_strconcat(script_path, "c", NULL);
 
2158
+       ret = _cmu_sieve_compile(interp, &sdata, script_path, compiled_path);
 
2159
+
 
2160
+       if (sdata.errors != NULL) {
 
2161
+               path = t_strconcat(script_path, ".err", NULL);
 
2162
+               //dovecot_sieve_write_error_file(&sdata, path);
 
2163
+               str_free(&sdata.errors);
 
2164
+       }
 
2165
+       if (ret <= 0)
 
2166
+               return ret;
 
2167
+
 
2168
+       memset(&mdata, 0, sizeof(mdata));
 
2169
+       mdata.context = context;
 
2170
+       mdata.id = sieve_runenv_get_mail_first_header(context, "Message-ID");
 
2171
+
 
2172
+       if ((ret = sieve_script_load(compiled_path, &bytecode)) != SIEVE_OK) {
 
2173
+               i_error("sieve_script_load(%s) failed: %d", compiled_path, ret);
 
2174
+               return -1;
 
2175
+       }
 
2176
+
 
2177
+       if (sieve_execute_bytecode(bytecode, interp,
 
2178
+                                  &sdata, &mdata) != SIEVE_OK)
 
2179
+               return -1;
 
2180
+
 
2181
+       return 1;
 
2182
+}
 
2183
+
 
2184
+struct sieve_implementation cmu_sieve = {
 
2185
+       MEMBER(name) "cmu",
 
2186
+       {       cmu_sieve_compile,
 
2187
+               cmu_sieve_run,
 
2188
+               sieve_listextensions
 
2189
+       }       
 
2190
+};
 
2191
+
 
2192
diff -r 894f003d9f5f src/lib-sieve/cmu/imparse.c
 
2193
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
2194
+++ b/src/lib-sieve/cmu/imparse.c       Sun May 04 16:00:59 2008 +0200
 
2195
@@ -0,0 +1,57 @@
 
2196
+/*
 
2197
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
 
2198
+ *
 
2199
+ * Redistribution and use in source and binary forms, with or without
 
2200
+ * modification, are permitted provided that the following conditions
 
2201
+ * are met:
 
2202
+ *
 
2203
+ * 1. Redistributions of source code must retain the above copyright
 
2204
+ *    notice, this list of conditions and the following disclaimer. 
 
2205
+ *
 
2206
+ * 2. Redistributions in binary form must reproduce the above copyright
 
2207
+ *    notice, this list of conditions and the following disclaimer in
 
2208
+ *    the documentation and/or other materials provided with the
 
2209
+ *    distribution.
 
2210
+ *
 
2211
+ * 3. The name "Carnegie Mellon University" must not be used to
 
2212
+ *    endorse or promote products derived from this software without
 
2213
+ *    prior written permission. For permission or any other legal
 
2214
+ *    details, please contact  
 
2215
+ *      Office of Technology Transfer
 
2216
+ *      Carnegie Mellon University
 
2217
+ *      5000 Forbes Avenue
 
2218
+ *      Pittsburgh, PA  15213-3890
 
2219
+ *      (412) 268-4387, fax: (412) 268-7395
 
2220
+ *      tech-transfer@andrew.cmu.edu
 
2221
+ *
 
2222
+ * 4. Redistributions of any form whatsoever must retain the following
 
2223
+ *    acknowledgment:
 
2224
+ *    "This product includes software developed by Computing Services
 
2225
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
 
2226
+ *
 
2227
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
2228
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 
2229
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
 
2230
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
2231
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 
2232
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 
2233
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
2234
+ *
 
2235
+ *
 
2236
+ */
 
2237
+#include "imparse.h"
 
2238
+
 
2239
+int imparse_isatom(const char *s)
 
2240
+{
 
2241
+    int len = 0;
 
2242
+
 
2243
+    if (!*s) return 0;
 
2244
+    for (; *s; s++) {
 
2245
+       len++;
 
2246
+       if (*s & 0x80 || *s < 0x1f || *s == 0x7f ||
 
2247
+           *s == ' ' || *s == '{' || *s == '(' || *s == ')' ||
 
2248
+           *s == '\"' || *s == '%' || *s == '*' || *s == '\\') return 0;
 
2249
+    }
 
2250
+    if (len >= 1024) return 0;
 
2251
+    return 1;
 
2252
+}
 
2253
diff -r 894f003d9f5f src/lib-sieve/cmu/imparse.h
 
2254
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
2255
+++ b/src/lib-sieve/cmu/imparse.h       Sun May 04 16:00:59 2008 +0200
 
2256
@@ -0,0 +1,6 @@
 
2257
+#ifndef __IMPARSE_H
 
2258
+#define __IMPARSE_H
 
2259
+
 
2260
+extern int imparse_isatom (const char *s);
 
2261
+
 
2262
+#endif
 
2263
diff -r 894f003d9f5f src/lib-sieve/cmu/libconfig.h
 
2264
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
2265
+++ b/src/lib-sieve/cmu/libconfig.h     Sun May 04 16:00:59 2008 +0200
 
2266
@@ -0,0 +1,8 @@
 
2267
+#ifndef __LIBCONFIG_H
 
2268
+#define __LIBCONFIG_H
 
2269
+
 
2270
+#define IMAPOPT_RFC3028_STRICT 1
 
2271
+
 
2272
+#define config_getswitch(n) 1
 
2273
+
 
2274
+#endif
 
2275
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/AUTHORS
 
2276
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
2277
+++ b/src/lib-sieve/cmu/libsieve/AUTHORS        Sun May 04 16:00:59 2008 +0200
 
2278
@@ -0,0 +1,9 @@
 
2279
+$Id$
 
2280
+
 
2281
+Larry Greenfield <leg+sieve@andrew.cmu.edu> wrote the first pass.
 
2282
+
 
2283
+Alexy Melnikov <alexey.melnikov@isode.com> submitted some bug fixes and 
 
2284
+improvements.
 
2285
+
 
2286
+Ken Murchison <ken@oceana.com> took the ball, added more extensions
 
2287
+than existed in the known world, and overall improved the code mightily.
 
2288
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/Makefile.am
 
2289
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
2290
+++ b/src/lib-sieve/cmu/libsieve/Makefile.am    Sun May 04 16:00:59 2008 +0200
 
2291
@@ -0,0 +1,76 @@
 
2292
+pkglibexecdir = $(libexecdir)/dovecot
 
2293
+
 
2294
+noinst_LTLIBRARIES = libsieve.la
 
2295
+
 
2296
+AM_YFLAGS = -d -p $*
 
2297
+
 
2298
+AM_CPPFLAGS = \
 
2299
+       -I$(top_srcdir) \
 
2300
+       -I$(top_srcdir)/src/lib \
 
2301
+       -I../
 
2302
+
 
2303
+addr-lex.c: addr-lex.l
 
2304
+       $(LEX) -t -Paddr addr-lex.l > addr-lex.c
 
2305
+
 
2306
+sieve-lex.c: sieve-lex.l
 
2307
+       $(LEX) -t sieve-lex.l > sieve-lex.c
 
2308
+
 
2309
+libsieve_la_SOURCES = \
 
2310
+       addr.y \
 
2311
+       sieve.y \
 
2312
+       addr-lex.l \
 
2313
+       sieve-lex.l \
 
2314
+       bc_dump.c \
 
2315
+       bc_emit.c \
 
2316
+       bc_eval.c \
 
2317
+       bc_generate.c \
 
2318
+       comparator.c \
 
2319
+       interp.c \
 
2320
+       message.c \
 
2321
+       parseaddr.c \
 
2322
+       script.c \
 
2323
+       sieve_err.c \
 
2324
+       tree.c
 
2325
+
 
2326
+noinst_HEADERS = \
 
2327
+       addr.h \
 
2328
+       bytecode.h \
 
2329
+       comparator.h \
 
2330
+       interp.h \
 
2331
+       message.h \
 
2332
+       parseaddr.h \
 
2333
+       script.h \
 
2334
+       sieve.h \
 
2335
+       sieve_err.h \
 
2336
+       sieve_interface.h \
 
2337
+       tree.h
 
2338
+
 
2339
+pkglibexec_PROGRAMS = sievec sieved
 
2340
+
 
2341
+sievec_SOURCES = \
 
2342
+       sievec.c \
 
2343
+       ../map.c \
 
2344
+       ../imparse.c
 
2345
+
 
2346
+sieved_SOURCES = \
 
2347
+       sieved.c \
 
2348
+       ../map.c
 
2349
+
 
2350
+sievec_LDADD = \
 
2351
+       libsieve.la \
 
2352
+       $(top_srcdir)/src/lib/liblib.a
 
2353
+
 
2354
+sieved_LDADD = \
 
2355
+       libsieve.la \
 
2356
+       $(top_srcdir)/src/lib/liblib.a
 
2357
+
 
2358
+notbuilt_sources =
 
2359
+
 
2360
+EXTRA_DIST = \
 
2361
+       addr-lex.l \
 
2362
+       sieve-lex.l \
 
2363
+       AUTHORS \
 
2364
+       COPYING \
 
2365
+       NEWS \
 
2366
+       README \
 
2367
+       $(notbuilt_sources)
 
2368
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/NEWS
 
2369
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
2370
+++ b/src/lib-sieve/cmu/libsieve/NEWS   Sun May 04 16:00:59 2008 +0200
 
2371
@@ -0,0 +1,84 @@
 
2372
+$Id$
 
2373
+
 
2374
+CMU Sieve 2.1
 
2375
+-------------
 
2376
+
 
2377
+- Compliant with RFC 3028.  As a result, fileinto and redirect only
 
2378
+  accept a single string and NOT a string-list.
 
2379
+
 
2380
+- Compliant with draft-martin-sieve-notify-01.  As a result, notify
 
2381
+  actions will need to be updated to the new syntax.
 
2382
+
 
2383
+CMU Sieve 2.0
 
2384
+-------------
 
2385
+
 
2386
+- Compliant with draft-showalter-sieve-11.txt and 
 
2387
+  draft-showalter-sieve-vacation-03.txt.
 
2388
+
 
2389
+- Added support for the regex, imapflags, notify and subaddress extensions.
 
2390
+  See README for references.
 
2391
+
 
2392
+- Verifies email addresses in redirect and vacation actions are syntactically
 
2393
+  correct (compliant with RFC822).
 
2394
+
 
2395
+- Run-time error reporting.
 
2396
+
 
2397
+- Changed callback interface to use callback contexts instead of individual
 
2398
+  parameters.  Also added an error string buffer for run-time error reporting.
 
2399
+
 
2400
+- Vacation will not reply to any message containing an "auto-submitted"
 
2401
+  header containing anything other than "no".
 
2402
+
 
2403
+CMU Sieve 1.4
 
2404
+-------------
 
2405
+
 
2406
+Now included with imapd distribution (hell, why not?).
 
2407
+
 
2408
+Error returning and recovering:
 
2409
+       added error recovering to the parser (but not much!)
 
2410
+       added error messages to the parser
 
2411
+
 
2412
+Working on error returning and error recovering.
 
2413
+       run-time errors
 
2414
+       detect some errors in lexer?
 
2415
+
 
2416
+Working on even better parsing:
 
2417
+       verify addresses could be addresses
 
2418
+       verify mailboxes could be mailboxes
 
2419
+       verify outgoing headers can be headers
 
2420
+
 
2421
+CMU Sieve 1.3
 
2422
+-------------
 
2423
+
 
2424
+Changed for integration with cyrus deliver.
 
2425
+
 
2426
+CMU Sieve 1.2
 
2427
+-------------
 
2428
+
 
2429
+Added additional callbacks (ok, so I want to make my integration with deliver
 
2430
+easier) and envelope and vacation support.
 
2431
+
 
2432
+Made it compile without libcyrus.
 
2433
+It should compile without libcyrus, but then it does not implement the
 
2434
+"address" test.         That's just too much work to do when I have a neato
 
2435
+library to do it for me.
 
2436
+
 
2437
+Todo:
 
2438
+- regex matching
 
2439
+
 
2440
+CMU Sieve 1.1
 
2441
+-------------
 
2442
+
 
2443
+- Updated to draft-showalter-sieve-07bis.txt
 
2444
+
 
2445
+- Simple API (see sieve_interface.h; currently mostly undocumented)
 
2446
+
 
2447
+- Implements all of the optional features except "envelope"
 
2448
+
 
2449
+- Maintains "if it parses, it probably runs" behavior. (Goal: minimize
 
2450
+  run-time errors.)
 
2451
+
 
2452
+CMU Sieve 1.0
 
2453
+-------------
 
2454
+
 
2455
+- prototype implementation
 
2456
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/README
 
2457
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
2458
+++ b/src/lib-sieve/cmu/libsieve/README Sun May 04 16:00:59 2008 +0200
 
2459
@@ -0,0 +1,59 @@
 
2460
+$Id$
 
2461
+
 
2462
+CMU Sieve 2.1
 
2463
+-------------
 
2464
+
 
2465
+This code is typically distributed as part of Cyrus imapd 1.6 and higher.
 
2466
+This code will be configured and compiled from the cyrus-imapd directory.
 
2467
+
 
2468
+Notes on implementation
 
2469
+-----------------------
 
2470
+
 
2471
+This is an implementation of a simple Sieve API.  This API is
 
2472
+well-suited for incorporating in other programs, but is not
 
2473
+extensible.  (If there is interest, we may implement an extensible API
 
2474
+in the future.)
 
2475
+
 
2476
+If you wish to compile Sieve without compiling all of imapd, you'll
 
2477
+have to create a Makefile for it.  I recommend you use Makefile.in as
 
2478
+a guide.
 
2479
+
 
2480
+It should compile without libcyrus, but then it does not implement the
 
2481
+"address" test.         That's just too much work to do when I have a neato
 
2482
+library to do it for me.
 
2483
+
 
2484
+There's a simple "test" application included, which is not built by
 
2485
+default (type "make test" to build it).  It expects:
 
2486
+
 
2487
+test <message> <script>
 
2488
+
 
2489
+And prints out the actions taken or errors encountered.  (This
 
2490
+implementation will attempt all the actions or no actions.)
 
2491
+
 
2492
+Questions and comments to:
 
2493
+Derrick Brashear (shadow+sieve@andrew.cmu.edu)
 
2494
+
 
2495
+References:
 
2496
+
 
2497
+[SIEVE] Showalter, T., "Sieve: A Mail Filtering Language",
 
2498
+RFC 3028, January, 2001.
 
2499
+
 
2500
+[VACATION] Showalter, T., "Sieve: Vacation Extension",
 
2501
+draft-showalter-sieve-vacation-04.txt, August, 2000.
 
2502
+
 
2503
+[IMAPFLAGS] Melnikov, A., "Sieve -- IMAP flag extension",
 
2504
+draft-melnikov-sieve-imapflags-03.txt, July, 2000.
 
2505
+
 
2506
+[NOTIFY] Martin, T., Segmuller, W.,
 
2507
+"Sieve -- An extension for providing instant notifications",
 
2508
+draft-martin-sieve-notify-01.txt, June, 2001.
 
2509
+
 
2510
+[REGEX] Murchison, K., "Sieve: Regular Expression Extension",
 
2511
+draft-murchison-sieve-regex-04.txt, August, 2001.
 
2512
+
 
2513
+[RELATIONAL] Segmuller, W., "Sieve Extension: Relational Tests",
 
2514
+RFC 3431, December 2002.
 
2515
+
 
2516
+[SUBADDR] Murchison, K., "Sieve Email Filtering -- Subaddress Extension",
 
2517
+RFC 3598, September 2003.
 
2518
+
 
2519
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/addr-lex.l
 
2520
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
2521
+++ b/src/lib-sieve/cmu/libsieve/addr-lex.l     Sun May 04 16:00:59 2008 +0200
 
2522
@@ -0,0 +1,91 @@
 
2523
+%{
 
2524
+/*
 
2525
+ * addr-lex.l -- RFC 822 address lexer
 
2526
+ * Ken Murchison
 
2527
+ * $Id$
 
2528
+ */
 
2529
+/***********************************************************
 
2530
+        Copyright 1999 by Carnegie Mellon University
 
2531
+
 
2532
+                      All Rights Reserved
 
2533
+
 
2534
+Permission to use, copy, modify, and distribute this software and its
 
2535
+documentation for any purpose and without fee is hereby granted,
 
2536
+provided that the above copyright notice appear in all copies and that
 
2537
+both that copyright notice and this permission notice appear in
 
2538
+supporting documentation, and that the name of Carnegie Mellon
 
2539
+University not be used in advertising or publicity pertaining to
 
2540
+distribution of the software without specific, written prior
 
2541
+permission.
 
2542
+
 
2543
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
2544
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
2545
+FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
 
2546
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
2547
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
2548
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 
2549
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
2550
+******************************************************************/
 
2551
+
 
2552
+#include "addr.h"
 
2553
+#include <string.h>
 
2554
+
 
2555
+#undef YY_INPUT
 
2556
+#define YY_INPUT(b, r, ms) (r = addrinput(b, ms))
 
2557
+
 
2558
+int addrinput(char *buf, int max_size);
 
2559
+void addrerror(const char *);
 
2560
+
 
2561
+static int ncom;       /* number of open comments */
 
2562
+%}
 
2563
+
 
2564
+%option noyywrap
 
2565
+%option nounput
 
2566
+%option prefix="addr"
 
2567
+
 
2568
+%x QSTRING DOMAINLIT COMMENT
 
2569
+
 
2570
+%%
 
2571
+
 
2572
+\"                             { BEGIN QSTRING; return yytext[0]; }
 
2573
+\[                             { BEGIN DOMAINLIT; return yytext[0]; }
 
2574
+\(                             { ncom = 1; BEGIN COMMENT; }
 
2575
+\)                             { addrerror("address parse error, "
 
2576
+                                         "unexpected `')'' "
 
2577
+                                         "(unbalanced comment)");
 
2578
+                                 yyterminate(); }
 
2579
+
 
2580
+[^\(\)<>@,;:\\".\[\] \n\r]+    return ATOM;
 
2581
+
 
2582
+[\t \n\r]+                     /* ignore whitespace */
 
2583
+.                              return yytext[0];
 
2584
+
 
2585
+<QSTRING>([^\n\r"\\]|\\.)*     return QTEXT;
 
2586
+<QSTRING>\"                    { BEGIN INITIAL; return yytext[0]; }
 
2587
+
 
2588
+<DOMAINLIT>([^\[\]\n\r\\]|\\.)*        return DTEXT;
 
2589
+<DOMAINLIT>\]                  { BEGIN INITIAL; return yytext[0]; }
 
2590
+
 
2591
+<COMMENT>([^\(\)\n\0\\]|\\.)*  /* ignore comments */
 
2592
+<COMMENT>\(                    ncom++;
 
2593
+<COMMENT>\)                    { ncom--; if (ncom == 0) BEGIN INITIAL; }
 
2594
+<COMMENT><<EOF>>               { addrerror("address parse error, "
 
2595
+                                         "expecting `')'' "
 
2596
+                                         "(unterminated comment)");
 
2597
+                                 yyterminate(); }
 
2598
+
 
2599
+%%
 
2600
+
 
2601
+/* take input from address string provided by sieve parser */
 
2602
+int addrinput(char *buf, int max_size)
 
2603
+{
 
2604
+    extern char *addrptr;      /* current position in address string */
 
2605
+    size_t n;                  /* number of characters to read from string */
 
2606
+
 
2607
+    n = (int)strlen(addrptr) < max_size ? (int)strlen(addrptr) : max_size;
 
2608
+    if (n > 0) {
 
2609
+       memcpy(buf, addrptr, n);
 
2610
+       addrptr += n;
 
2611
+    }
 
2612
+    return n;
 
2613
+}
 
2614
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/addr.y
 
2615
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
2616
+++ b/src/lib-sieve/cmu/libsieve/addr.y Sun May 04 16:00:59 2008 +0200
 
2617
@@ -0,0 +1,91 @@
 
2618
+%{
 
2619
+/*
 
2620
+ * addr.y -- RFC 822 address parser
 
2621
+ * Ken Murchison
 
2622
+ * $Id$
 
2623
+ */
 
2624
+/***********************************************************
 
2625
+        Copyright 1999 by Carnegie Mellon University
 
2626
+
 
2627
+                      All Rights Reserved
 
2628
+
 
2629
+Permission to use, copy, modify, and distribute this software and its
 
2630
+documentation for any purpose and without fee is hereby granted,
 
2631
+provided that the above copyright notice appear in all copies and that
 
2632
+both that copyright notice and this permission notice appear in
 
2633
+supporting documentation, and that the name of Carnegie Mellon
 
2634
+University not be used in advertising or publicity pertaining to
 
2635
+distribution of the software without specific, written prior
 
2636
+permission.
 
2637
+
 
2638
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
2639
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
2640
+FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
 
2641
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
2642
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
2643
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 
2644
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
2645
+******************************************************************/
 
2646
+
 
2647
+#include <stdlib.h>
 
2648
+#include <string.h>
 
2649
+
 
2650
+#include "addr.h"
 
2651
+#include "script.h"
 
2652
+#include "xmalloc.h"
 
2653
+    
 
2654
+int addrerror(char *msg);
 
2655
+extern int yylex(void);
 
2656
+
 
2657
+#define YYERROR_VERBOSE /* i want better error messages! */
 
2658
+%}
 
2659
+
 
2660
+%token ATOM QTEXT DTEXT
 
2661
+
 
2662
+%%
 
2663
+sieve_address: addrspec                        /* simple address */
 
2664
+       | phrase '<' addrspec '>'       /* name & addr-spec */
 
2665
+       ;
 
2666
+
 
2667
+addrspec: localpart '@' domain         /* global-address */
 
2668
+       ;
 
2669
+
 
2670
+localpart: word                                /* uninterpreted, case-preserved */
 
2671
+       | word '.' localpart
 
2672
+       ;
 
2673
+
 
2674
+domain: subdomain
 
2675
+       | subdomain '.' domain
 
2676
+       ;
 
2677
+
 
2678
+subdomain: domainref
 
2679
+       | domainlit
 
2680
+       ;
 
2681
+
 
2682
+domainref: ATOM                                /* symbolic reference */
 
2683
+       ;
 
2684
+
 
2685
+domainlit: '[' DTEXT ']'
 
2686
+       ;
 
2687
+
 
2688
+phrase: word
 
2689
+       | word phrase
 
2690
+       ;
 
2691
+
 
2692
+word: ATOM
 
2693
+       | qstring
 
2694
+       ;
 
2695
+
 
2696
+qstring: '"' QTEXT '"'
 
2697
+       ;
 
2698
+
 
2699
+%%
 
2700
+
 
2701
+/* copy address error message into buffer provided by sieve parser */
 
2702
+int addrerror(char *s)
 
2703
+{
 
2704
+    extern char addrerr[ADDRERR_SIZE];
 
2705
+    
 
2706
+    strlcpy(addrerr, s, sizeof(addrerr));
 
2707
+    return 0;
 
2708
+}
 
2709
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/bc_dump.c
 
2710
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
2711
+++ b/src/lib-sieve/cmu/libsieve/bc_dump.c      Sun May 04 16:00:59 2008 +0200
 
2712
@@ -0,0 +1,304 @@
 
2713
+/* bc_generate.c -- sieve bytecode- almost flattened bytecode
 
2714
+ * Rob Siemborski
 
2715
+ * $Id$
 
2716
+ */
 
2717
+/***********************************************************
 
2718
+        Copyright 2001 by Carnegie Mellon University
 
2719
+
 
2720
+                      All Rights Reserved
 
2721
+
 
2722
+Permission to use, copy, modify, and distribute this software and its
 
2723
+documentation for any purpose and without fee is hereby granted,
 
2724
+provided that the above copyright notice appear in all copies and that
 
2725
+both that copyright notice and this permission notice appear in
 
2726
+supporting documentation, and that the name of Carnegie Mellon
 
2727
+University not be used in advertising or publicity pertaining to
 
2728
+distribution of the software without specific, written prior
 
2729
+permission.
 
2730
+
 
2731
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
2732
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
2733
+FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
 
2734
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
2735
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
2736
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 
2737
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
2738
+******************************************************************/
 
2739
+
 
2740
+#ifdef HAVE_CONFIG_H
 
2741
+#include <config.h>
 
2742
+#endif
 
2743
 
2744
+#include "sieve_interface.h"
 
2745
+#include "bytecode.h"
 
2746
+
 
2747
 
2748
+struct bytecode_info 
 
2749
+{
 
2750
+    bytecode_t *data;/* pointer to almost-flat bytecode */
 
2751
+    size_t scriptend; /* used by emit code to know final length of bytecode */
 
2752
+    size_t reallen; /* allocated length of 'data' */
 
2753
+};
 
2754
+
 
2755
+#if DUMPCODE
 
2756
+
 
2757
+/*this would work a lot better if we actually could tell how many levels deep in if statements we were.  currently it doesn't know*/
 
2758
+
 
2759
+static void print_spaces(int n)
 
2760
+{
 
2761
+    int temp_n=0;
 
2762
+    while(temp_n++ < (n))
 
2763
+       putchar(' ');
 
2764
+}
 
2765
+
 
2766
+
 
2767
+/* Dump a stringlist.  Return the last address used by the list */
 
2768
+static int dump_sl(bytecode_info_t *d, int ip, int level) 
 
2769
+{
 
2770
+    int numstr = d->data[ip].listlen;
 
2771
+    int i;
 
2772
+    
 
2773
+    for(i=0; i<numstr; i++) {
 
2774
+       print_spaces(level*4);
 
2775
+       printf(" {%d}",d->data[++ip].len);
 
2776
+       printf("%s\n",d->data[++ip].str);
 
2777
+    }
 
2778
+    
 
2779
+    return ip;
 
2780
+}
 
2781
+
 
2782
+static int dump_test(bytecode_info_t *d, int ip, int level);
 
2783
+
 
2784
+/* Dump a testlist.  Return the last address used by the list */
 
2785
+static int dump_tl(bytecode_info_t *d, int ip, int level) 
 
2786
+{
 
2787
+    int numtest = d->data[ip].listlen;
 
2788
+    int i;
 
2789
+    
 
2790
+    for(i=0; i<numtest; i++) {
 
2791
+       print_spaces(level*4);
 
2792
+       printf(" (until %d)\n", d->data[++ip].jump);
 
2793
+       ip = dump_test(d, ++ip, level);
 
2794
+    }
 
2795
+    
 
2796
+    return ip;
 
2797
+}
 
2798
+
 
2799
+/* Dump a test, return the last address used by the test */
 
2800
+static int dump_test(bytecode_info_t *d, int ip, int level ) {
 
2801
+
 
2802
+    print_spaces(level*4);
 
2803
+    switch(d->data[ip].op) {
 
2804
+    case BC_TRUE:
 
2805
+       printf("%d: TRUE\n",ip);
 
2806
+       break;
 
2807
+
 
2808
+    case BC_FALSE:
 
2809
+       printf("%d: FALSE\n",ip);
 
2810
+       break;
 
2811
+
 
2812
+    case BC_NOT:
 
2813
+       printf("%d: NOT TEST(\n",ip++);
 
2814
+       /*   printf("  (until %d)\n", d->data[ip++].jump);*/
 
2815
+       ip = dump_test(d,ip, level);
 
2816
+       print_spaces(level*4);
 
2817
+       printf("    )\n");
 
2818
+       break;
 
2819
+
 
2820
+    case BC_SIZE:
 
2821
+       printf("%d: SIZE TAG(%d) NUM(%d)\n",ip,
 
2822
+              d->data[ip+1].value, d->data[ip+2].value);
 
2823
+       ip+=2;
 
2824
+       break;
 
2825
+
 
2826
+    case BC_EXISTS:
 
2827
+       printf("%d: EXISTS\n",ip++);
 
2828
+       ip = dump_sl(d,ip,level);
 
2829
+       break;
 
2830
+
 
2831
+    case BC_ALLOF:
 
2832
+       printf("%d: ALLOF (\n",ip++);
 
2833
+       ip = dump_tl(d,ip,level);
 
2834
+       print_spaces(level*4);
 
2835
+       printf(")\n");
 
2836
+       break;
 
2837
+
 
2838
+    case BC_ANYOF:
 
2839
+       printf("%d: ANYOF (\n",ip++);
 
2840
+       ip = dump_tl(d,ip, level);
 
2841
+         print_spaces(level*4);
 
2842
+       printf(")\n");
 
2843
+       break;
 
2844
+           
 
2845
+    case BC_HEADER:
 
2846
+       printf("%d: HEADER (\n",ip++);
 
2847
+       print_spaces(level*4);
 
2848
+       if (d->data[ip].value == B_COUNT || d->data[ip].value == B_VALUE)
 
2849
+       {
 
2850
+           printf("      MATCH:%d  RELATION:%d  COMP:%d HEADERS:\n", 
 
2851
+                  d->data[ip].value, d->data[ip+1].value,d->data[ip+2].value);
 
2852
+       } else {
 
2853
+           printf("      MATCH:%d COMP:%d HEADERS:\n",d->data[ip].value, d->data[ip+2].value);
 
2854
+       }
 
2855
+       ip+=3;
 
2856
+       ip = dump_sl(d,ip,level);
 
2857
+       ip++;
 
2858
+       print_spaces(level*4);
 
2859
+       printf("      DATA:\n");
 
2860
+       ip = dump_sl(d,ip,level);
 
2861
+       break;
 
2862
+       
 
2863
+    case BC_ADDRESS:
 
2864
+    case BC_ENVELOPE:
 
2865
+       printf("%d: %s (\n",ip++,
 
2866
+              d->data[ip].op == BC_ADDRESS ? "ADDRESS" : "ENVELOPE");
 
2867
+       print_spaces(level*4);
 
2868
+       if (d->data[ip].value == B_COUNT || d->data[ip].value == B_VALUE)
 
2869
+       {
 
2870
+           printf("      MATCH:%d RELATION: %d COMP: %d TYPE: %d HEADERS:\n", 
 
2871
+                  d->data[ip].value, d->data[ip+1].value, d->data[ip+2].value, d->data[ip+3].value);
 
2872
+       } else {
 
2873
+           printf("      MATCH:%d COMP:%d TYPE:%d HEADERS:\n",
 
2874
+                  d->data[ip].value,d->data[ip+1].value,d->data[ip+3].value);
 
2875
+       }
 
2876
+       ip+=4;
 
2877
+       ip = dump_sl(d,ip,level); ip++;
 
2878
+       print_spaces(level*4);
 
2879
+       printf("      DATA:\n");
 
2880
+       ip = dump_sl(d,ip,level);
 
2881
+       break;
 
2882
+
 
2883
+    default:
 
2884
+       printf("%d: TEST(%d)\n",ip,d->data[ip].op);
 
2885
+       break;
 
2886
+    }
 
2887
+
 
2888
+    return ip;
 
2889
+}
 
2890
+
 
2891
+void dump(bytecode_info_t *d, int level) 
 
2892
+{
 
2893
+    int i;
 
2894
+    printf("Dumping almost flattened bytecode\n\n");
 
2895
+    
 
2896
+    if(!d) return;
 
2897
+    
 
2898
+    for(i=0; i<d->scriptend; i++) {
 
2899
+       print_spaces(level*4);
 
2900
+       switch(d->data[i].op) {
 
2901
+       case B_REJECT:
 
2902
+           printf("%d: REJECT {%d}%s\n",i,
 
2903
+                  d->data[i+1].len,d->data[i+2].str);
 
2904
+           i+=2;
 
2905
+           break;
 
2906
+       case B_IF:
 
2907
+           if (d->data[i+3].jump== -1)
 
2908
+           {
 
2909
+               printf("%d: IF THEN(%d) POST(%d) TEST(\n",i,
 
2910
+                      d->data[i+1].jump,d->data[i+2].jump);
 
2911
+           }
 
2912
+           else
 
2913
+           {
 
2914
+               printf("%d: IF THEN(%d) ELSE(%d) POST(%d) TEST(\n",i,
 
2915
+                      d->data[i+1].jump,d->data[i+2].jump,
 
2916
+                      d->data[i+3].jump);
 
2917
+           }
 
2918
+           i = dump_test(d,i+4, level+1);
 
2919
+           printf(")\n");
 
2920
+           break;
 
2921
+
 
2922
+       case B_STOP:
 
2923
+           printf("%d: STOP\n",i);
 
2924
+           break;
 
2925
+
 
2926
+       case B_DISCARD:
 
2927
+           printf("%d: DISCARD\n",i);
 
2928
+           break;
 
2929
+           
 
2930
+       case B_KEEP:
 
2931
+           printf("%d: KEEP\n",i);
 
2932
+           break;
 
2933
+
 
2934
+       case B_MARK:
 
2935
+           printf("%d: MARK\n",i);
 
2936
+           break;
 
2937
+
 
2938
+       case B_UNMARK:
 
2939
+           printf("%d: UNMARK\n",i);
 
2940
+           break;
 
2941
+
 
2942
+       case B_FILEINTO:
 
2943
+           printf("%d: FILEINTO {%d}%s\n",i,
 
2944
+                  d->data[i+1].len,d->data[i+2].str);
 
2945
+           i+=2;
 
2946
+           break;
 
2947
+
 
2948
+       case B_REDIRECT:
 
2949
+           printf("%d: REDIRECT {%d}%s\n",i,
 
2950
+                  d->data[i+1].len,d->data[i+2].str);
 
2951
+           i+=2;
 
2952
+           break;
 
2953
+
 
2954
+       case B_SETFLAG:
 
2955
+           printf("%d: SETFLAG\n",i);
 
2956
+           i=dump_sl(d,++i, level);
 
2957
+           break;
 
2958
+
 
2959
+       case B_ADDFLAG:
 
2960
+           printf("%d: ADDFLAG\n",i);
 
2961
+           i=dump_sl(d,++i,level);
 
2962
+           break;
 
2963
+
 
2964
+       case B_REMOVEFLAG:
 
2965
+           printf("%d: REMOVEFLAG\n",i);
 
2966
+           i=dump_sl(d,++i,level);
 
2967
+           break;
 
2968
+
 
2969
+       case B_DENOTIFY:
 
2970
+           printf("%d: DENOTIFY priority %d,comp %d %d  %s\n", 
 
2971
+                  i,
 
2972
+                  d->data[i+1].value,
 
2973
+                  d->data[i+2].value,
 
2974
+                  d->data[i+3].value,
 
2975
+                  (d->data[i+4].len == -1 ? "[nil]" : d->data[i+5].str));
 
2976
+           i+=5;
 
2977
+           break;
 
2978
+
 
2979
+       case B_NOTIFY: 
 
2980
+           printf("%d: NOTIFY\n   METHOD(%s),\n   ID(%s),\n   OPTIONS",
 
2981
+                  i,
 
2982
+                  d->data[i+2].str,
 
2983
+                  (d->data[i+3].len == -1 ? "[nil]" : d->data[i+4].str));
 
2984
+           i+=5;
 
2985
+           i=dump_sl(d,i,level);
 
2986
+           printf("   PRIORITY(%d),\n   MESSAGE({%d}%s)\n", 
 
2987
+                  d->data[i+1].value, d->data[i+2].len,d->data[i+3].str);
 
2988
+           i+=3;
 
2989
+           break;
 
2990
+
 
2991
+       case B_VACATION:
 
2992
+           printf("%d:VACATION\n",i);
 
2993
+           i++;
 
2994
+           i=dump_sl(d,i,level);
 
2995
+           printf("SUBJ({%d}%s) MESG({%d}%s)\n DAYS(%d) MIME(%d)\n", 
 
2996
+                  d->data[i+1].len, (d->data[i+1].len == -1 ? "[nil]" : d->data[i+2].str),
 
2997
+                  d->data[i+3].len, (d->data[i+3].len == -1 ? "[nil]" : d->data[i+4].str),
 
2998
+                  d->data[i+5].value, d->data[i+6].value);
 
2999
+           i+=6;
 
3000
+       
 
3001
+           break;
 
3002
+       case B_JUMP:
 
3003
+           printf("%d: JUMP HUH?  this shouldn't be here>?!",i);
 
3004
+           break;
 
3005
+       case B_NULL:
 
3006
+           printf("%d: NULL\n",i);
 
3007
+           break;
 
3008
+       default:
 
3009
+           printf("%d: %d\n",i,d->data[i].op);
 
3010
+           break;
 
3011
+       }
 
3012
+    }
 
3013
+    printf("full len is: %d\n", d->scriptend);
 
3014
+}
 
3015
+#endif
 
3016
+
 
3017
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/bc_emit.c
 
3018
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
3019
+++ b/src/lib-sieve/cmu/libsieve/bc_emit.c      Sun May 04 16:00:59 2008 +0200
 
3020
@@ -0,0 +1,672 @@
 
3021
+/* bc_emit.c -- sieve bytecode - pass 2 of the compiler
 
3022
+ * Rob Siemborski
 
3023
+ * Jen Smith
 
3024
+ * $Id$
 
3025
+ */
 
3026
+/***********************************************************
 
3027
+        Copyright 2001 by Carnegie Mellon University
 
3028
+
 
3029
+                      All Rights Reserved
 
3030
+
 
3031
+Permission to use, copy, modify, and distribute this software and its
 
3032
+documentation for any purpose and without fee is hereby granted,
 
3033
+provided that the above copyright notice appear in all copies and that
 
3034
+both that copyright notice and this permission notice appear in
 
3035
+supporting documentation, and that the name of Carnegie Mellon
 
3036
+University not be used in advertising or publicity pertaining to
 
3037
+distribution of the software without specific, written prior
 
3038
+permission.
 
3039
+
 
3040
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
3041
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
3042
+FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
 
3043
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
3044
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
3045
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 
3046
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
3047
+******************************************************************/
 
3048
+
 
3049
+#ifdef HAVE_CONFIG_H
 
3050
+#include <config.h>
 
3051
+#endif
 
3052
+
 
3053
+#include "xmalloc.h"
 
3054
+#include "sieve_interface.h"
 
3055
+
 
3056
 
3057
+#include "bytecode.h"
 
3058
+
 
3059
+#include <sys/types.h>
 
3060
+#include <unistd.h>
 
3061
+
 
3062
+
 
3063
+#if DUMPCODE
 
3064
+void dump(bytecode_info_t *d);
 
3065
+#endif
 
3066
+
 
3067
+static inline int write_int (int fd, int x)
 
3068
+{
 
3069
+    int y=htonl(x);
 
3070
+    return (write(fd, &y, sizeof(int)));
 
3071
+}
 
3072
 
3073
+    
 
3074
+
 
3075
+struct bytecode_info 
 
3076
+{
 
3077
+    bytecode_t *data;/* pointer to almost-flat bytecode */
 
3078
+    size_t scriptend; /* used by emit code to know final length of bytecode  */
 
3079
+    size_t reallen; /* allocated length of 'data' */
 
3080
+};
 
3081
+
 
3082
+/* Pad null bytes onto the end of the string we just wrote */
 
3083
+/* returns -1 on failure or number of bytes written on success */
 
3084
+static int align_string(int fd, int string_len) 
 
3085
+{
 
3086
+    /* Keep in mind that we always want to pad a string with *at least*
 
3087
+     * one zero, that's why sometimes we have to pad with 4 */
 
3088
+    int needed = sizeof(int) - (string_len % sizeof(int));
 
3089
+    if (needed>= 0 && needed <=4)
 
3090
+    {
 
3091
+       if(write(fd, "\0\0\0\0", needed) == -1) return -1;
 
3092
+    }
 
3093
+    return needed;
 
3094
+}
 
3095
+
 
3096
+/*all functions keep codep up to date as they use it.
 
3097
+  the amount that has been written to the file is maintained by the
 
3098
+  filelen variable in bc_action_emit
 
3099
+  the other bc_xxx_emit funtions keep track of how much they (and any functions they call) have written and return this value
 
3100
+*/
 
3101
+
 
3102
+
 
3103
+/* Write out a stringlist to a given file descriptor.
 
3104
+ * return # of bytes written on success and -1 on error */
 
3105
+
 
3106
+/* stringlist: <# listitems>
 
3107
+               <pos of listend (bytes)>
 
3108
+               <string:(size)(aligned string)>
 
3109
+*/
 
3110
+static int bc_stringlist_emit(int fd, int *codep, bytecode_info_t *bc) 
 
3111
+{
 
3112
+    int len = bc->data[(*codep)++].len;
 
3113
+    int i;
 
3114
+    int ret;
 
3115
+    int wrote = 2*sizeof(int);
 
3116
+    int begin,end;
 
3117
+
 
3118
+    /* Write out number of items in the list */
 
3119
+    if (write_int(fd, len)== -1) return -1 ;
 
3120
+    
 
3121
+    /* skip one spot end of list position*/
 
3122
+    begin=lseek(fd,0,SEEK_CUR);
 
3123
+    lseek(fd,sizeof(int),SEEK_CUR);
 
3124
+    
 
3125
+    /* Loop through all the items of the list, writing out length and string
 
3126
+     * in sequence */
 
3127
+    for(i=0; i < len; i++)
 
3128
+    {
 
3129
+       int datalen = bc->data[(*codep)++].len;
 
3130
+       
 
3131
+       if(write_int(fd, datalen) == -1) return -1;
 
3132
+       wrote += sizeof(int);
 
3133
+       
 
3134
+       if(write(fd, bc->data[(*codep)++].str, datalen) == -1) return -1;
 
3135
+       wrote += datalen;
 
3136
+       
 
3137
+       ret = align_string(fd,datalen);
 
3138
+       if(ret == -1) return -1;
 
3139
+       
 
3140
+       wrote+=ret;
 
3141
+    }
 
3142
+    end=lseek(fd,0,SEEK_CUR);
 
3143
 
3144
+    /* go back and write end of list position */
 
3145
+    lseek(fd,begin,SEEK_SET);
 
3146
+    if(write_int(fd, end) == -1) return -1;
 
3147
+
 
3148
+    /* return to the end */
 
3149
+    lseek(fd,end,SEEK_SET);
 
3150
+    return wrote;
 
3151
+}
 
3152
+
 
3153
+static int bc_test_emit(int fd, int *codep, bytecode_info_t *bc);
 
3154
+
 
3155
+/* Write out a testlist to a given file descriptor.
 
3156
+ * return # of bytes written on success and -1 on error */
 
3157
+static int bc_testlist_emit(int fd, int *codep, bytecode_info_t *bc) 
 
3158
+{
 
3159
+    int len = bc->data[(*codep)++].len;
 
3160
+    int i;
 
3161
+    int ret;
 
3162
+    int begin, end;
 
3163
+    int wrote = 2*sizeof(int);
 
3164
+        
 
3165
+    /* Write out number of items in the list */
 
3166
+    if(write_int(fd, len)== -1) return -1;
 
3167
+
 
3168
+    /* skip one spot for end of list position*/
 
3169
+    begin = lseek(fd, 0, SEEK_CUR);
 
3170
+    lseek(fd, sizeof(int), SEEK_CUR);
 
3171
+      
 
3172
+    /* Loop through all the items of the list, writing out each
 
3173
+     * test as we reach it in sequence. */
 
3174
+    for(i=0; i < len; i++) {
 
3175
+       int nextcodep = bc->data[(*codep)++].jump;
 
3176
+       
 
3177
+       ret = bc_test_emit(fd, codep, bc);
 
3178
+       if(ret < 0 ) return -1;
 
3179
+       
 
3180
+       wrote+=ret;
 
3181
+       *codep = nextcodep;
 
3182
+    }
 
3183
+    end = lseek(fd, 0, SEEK_CUR);
 
3184
+
 
3185
+    /* go back and write the end of list position */
 
3186
+    lseek(fd,begin,SEEK_SET);
 
3187
+    if(write_int(fd, end) == -1) return -1;
 
3188
+
 
3189
+    /*return to the end */
 
3190
+    lseek(fd,end,SEEK_SET);
 
3191
+
 
3192
+    return wrote;
 
3193
+}
 
3194
+
 
3195
+/* emit the bytecode for a test.  returns -1 on failure or size of
 
3196
+ * emitted bytecode on success */
 
3197
+static int bc_test_emit(int fd, int *codep, bytecode_info_t *bc) 
 
3198
+{
 
3199
+    int wrote=0;/* Relative offset to account for interleaved strings */
 
3200
+    
 
3201
+    
 
3202
+    int ret; /* Temporary Return Value Variable */
 
3203
+    
 
3204
+    /* Output this opcode */
 
3205
+    if(write_int(fd, bc->data[(*codep)].op) == -1)
 
3206
+       return -1;
 
3207
+    wrote += sizeof(int);
 
3208
+    
 
3209
+    switch(bc->data[(*codep)++].op) {
 
3210
+    case BC_TRUE:
 
3211
+    case BC_FALSE:
 
3212
+       /* No parameter opcodes */
 
3213
+       break;
 
3214
+       
 
3215
+    case BC_NOT:
 
3216
+    {
 
3217
+       /* Single parameter: another test */
 
3218
+       ret = bc_test_emit(fd, codep, bc);
 
3219
+       if(ret < 0)
 
3220
+           return -1;
 
3221
+       else
 
3222
+           wrote+=ret;
 
3223
+       break;
 
3224
+    }
 
3225
+    
 
3226
+    case BC_ALLOF:
 
3227
+    case BC_ANYOF:
 
3228
+       /*where we jump to?*/
 
3229
+       /* Just drop a testlist */
 
3230
+       ret = bc_testlist_emit(fd, codep, bc);
 
3231
+       if(ret < 0)
 
3232
+           return -1;
 
3233
+       else
 
3234
+           wrote+=ret;
 
3235
+       break;
 
3236
+       
 
3237
+    case BC_SIZE:
 
3238
+       /* Drop tag and number */
 
3239
+       if(write_int(fd, bc->data[(*codep)].value) == -1)
 
3240
+           return -1;
 
3241
+       if(write_int(fd, bc->data[(*codep)+1].value) == -1)
 
3242
+           return -1;
 
3243
+       
 
3244
+       wrote += 2 * sizeof(int);
 
3245
+       (*codep) += 2;
 
3246
+       break;
 
3247
+       
 
3248
+    case BC_EXISTS:
 
3249
+    {
 
3250
+       int ret;
 
3251
+       ret = bc_stringlist_emit(fd, codep, bc);
 
3252
+       if(ret < 0) return -1;
 
3253
+       wrote += ret;
 
3254
+       break;
 
3255
+    }
 
3256
+    
 
3257
+    case BC_HEADER:
 
3258
+    {
 
3259
+       int ret;
 
3260
+       /* Drop match type */
 
3261
+       if(write_int(fd, bc->data[(*codep)].value) == -1)
 
3262
+           return -1;
 
3263
+       wrote += sizeof(int);
 
3264
+       (*codep)++;
 
3265
+       /*drop comparator */
 
3266
+       if(write_int(fd, bc->data[(*codep)].value) == -1)
 
3267
+           return -1;
 
3268
+       wrote += sizeof(int);
 
3269
+       (*codep)++;    
 
3270
+       /*now drop relation*/
 
3271
+       if(write_int(fd, bc->data[(*codep)].value) == -1)
 
3272
+           return -1;
 
3273
+       wrote += sizeof(int);
 
3274
+       (*codep)++;
 
3275
+       /* Now drop headers */
 
3276
+       ret = bc_stringlist_emit(fd, codep, bc);
 
3277
+       if(ret < 0) return -1;
 
3278
+       wrote+=ret;
 
3279
+       /* Now drop data */
 
3280
+       ret = bc_stringlist_emit(fd, codep, bc);
 
3281
+       if(ret < 0) return -1;
 
3282
+       wrote+=ret;
 
3283
+       break;
 
3284
+    }
 
3285
+    
 
3286
+    case BC_ADDRESS:
 
3287
+    case BC_ENVELOPE:
 
3288
+    {
 
3289
+       int ret;
 
3290
+       /* Drop match type */
 
3291
+       if(write_int(fd, bc->data[(*codep)].value) == -1)
 
3292
+           return -1;
 
3293
+       wrote += sizeof(int);
 
3294
+       (*codep)++;
 
3295
+       /*drop comparator */
 
3296
+       if(write_int(fd, bc->data[(*codep)].value) == -1)
 
3297
+           return -1;
 
3298
+       wrote += sizeof(int);
 
3299
+       (*codep)++;
 
3300
+       /*now drop relation*/
 
3301
+       if(write_int(fd, bc->data[(*codep)].value) == -1)
 
3302
+           return -1;
 
3303
+       wrote += sizeof(int);
 
3304
+       (*codep)++;
 
3305
+       /*now drop address part*/
 
3306
+       if(write_int(fd, bc->data[(*codep)].value) == -1)
 
3307
+           return -1;
 
3308
+       wrote += sizeof(int);
 
3309
+       (*codep)++;
 
3310
+       /* Now drop headers */
 
3311
+       ret = bc_stringlist_emit(fd, codep, bc);
 
3312
+       if(ret < 0) return -1;
 
3313
+       wrote+=ret;
 
3314
+       /* Now drop data */
 
3315
+       ret = bc_stringlist_emit(fd, codep, bc);
 
3316
+       if(ret < 0) return -1;
 
3317
+       wrote+=ret;
 
3318
+       break;
 
3319
+    }
 
3320
+    
 
3321
+    default:
 
3322
+       /* Unknown testcode? */
 
3323
+       return -1;
 
3324
+    }
 
3325
+    return wrote;
 
3326
+}
 
3327
+
 
3328
+/* emit the bytecode to a file descriptor given a flattened parse tree
 
3329
+ * returns -1 on failure, size of emitted bytecode on success.
 
3330
+ *
 
3331
+ * this takes care of everything except the comparisons */
 
3332
+static int bc_action_emit(int fd, int codep, int stopcodep,
 
3333
+                         bytecode_info_t *bc, int filelen) 
 
3334
+{
 
3335
+    int len; /* Temporary Length Variable */
 
3336
+    int ret; /* Temporary Return Value Variable */
 
3337
+    int start_filelen = filelen;
 
3338
+    int i;
 
3339
+    
 
3340
+    /*debugging variable to check filelen*/
 
3341
+    /*int location;*/
 
3342
+    
 
3343
+    /*syslog(LOG_DEBUG, "entered bc_action_emit with filelen: %d", filelen);*/
 
3344
+    
 
3345
+    /* All non-string data MUST be sizeof(int)
 
3346
+       byte alligned so the end of each string may require a pad */
 
3347
+    /*
 
3348
+     * Note that for purposes of jumps you must multiply codep by sizeof(int)
 
3349
+     */
 
3350
+    while(codep < stopcodep) {
 
3351
+       /* Output this opcode */
 
3352
+       if(write_int(fd, bc->data[codep].op) == -1)
 
3353
+           return -1; 
 
3354
+       
 
3355
+       filelen+=sizeof(int);
 
3356
+       
 
3357
+       switch(bc->data[codep++].op) {
 
3358
+
 
3359
+       case B_IF:
 
3360
+       {
 
3361
+           /* IF
 
3362
+            *  test
 
3363
+            *  jump (false condition)
 
3364
+            *  then
 
3365
+            * (if there is an else) jump(finish) 
 
3366
+            * (if there is an else) else
 
3367
+            */
 
3368
+
 
3369
+           int testEndLoc=-1;
 
3370
+           int testdist, thendist, elsedist;
 
3371
+           int c;
 
3372
+           
 
3373
+           int jumpFalseLoc=-1;/*this is the location that is being reserved
 
3374
+                                 for the first jump command
 
3375
+                                 we jump to the false condition of the test*/
 
3376
+           
 
3377
+           int jumpEndLoc=-1; /* this is the location that is being reserved
 
3378
+                                 for the optional jump command
 
3379
+                                 it jumps over the else statement to the end*/
 
3380
+           int jumpto=-1;
 
3381
+           int jumpop= B_JUMP;
 
3382
+
 
3383
+           /*leave space to store the location of end of the test*/
 
3384
+           ret = lseek(fd, sizeof(int), SEEK_CUR);
 
3385
+           if(ret == -1) return ret;
 
3386
+           
 
3387
+           testEndLoc=filelen;
 
3388
+           filelen+=sizeof(int);
 
3389
+           
 
3390
+           /* spew the test */
 
3391
+
 
3392
+           c=codep+3;
 
3393
+           testdist = bc_test_emit(fd, &c, bc);
 
3394
+           if(testdist == -1)return -1;
 
3395
+           filelen +=testdist;
 
3396
+           
 
3397
+            /*store the location for hte end of the test
 
3398
+            *this is important for short circuiting of allof/anyof*/
 
3399
+           jumpto=filelen/4;
 
3400
+           if(lseek(fd, testEndLoc, SEEK_SET) == -1)
 
3401
+               return -1;
 
3402
+           if(write_int(fd,jumpto) == -1)
 
3403
+               return -1;
 
3404
+
 
3405
+           if(lseek(fd,filelen,SEEK_SET) == -1)
 
3406
+               return -1;
 
3407
+
 
3408
+           /* leave space for jump */
 
3409
+           if(write_int(fd, jumpop) == -1)
 
3410
+               return -1;
 
3411
+           ret = lseek(fd, sizeof(int), SEEK_CUR);
 
3412
+           if(ret == -1)
 
3413
+               return ret;
 
3414
+           jumpFalseLoc=filelen+sizeof(int);
 
3415
+           
 
3416
+           filelen +=2*sizeof(int); /*jumpop + jump*/
 
3417
+           
 
3418
+           /* spew the then code */ 
 
3419
+           thendist = bc_action_emit(fd, bc->data[codep].value,
 
3420
+                                     bc->data[codep+1].value, bc,
 
3421
+                                     filelen);
 
3422
+        
 
3423
+           filelen+=thendist;
 
3424
+                   
 
3425
+           /* there is an else case */
 
3426
+           if(bc->data[codep+2].value != -1)
 
3427
+           {
 
3428
+               /* leave space for jump */
 
3429
+               if(write_int(fd, jumpop) == -1)
 
3430
+                   return -1;
 
3431
+               ret = lseek(fd, sizeof(int), SEEK_CUR);
 
3432
+               if(ret == -1)
 
3433
+                   return ret;
 
3434
+
 
3435
+               jumpEndLoc=filelen+sizeof(int);
 
3436
+               filelen+=2*sizeof(int);/*jumpop + jump*/
 
3437
+           }
 
3438
+         
 
3439
+           /*put previous jump to the end of the then code,
 
3440
+            *or the end of the jump if there is an else case */
 
3441
+           jumpto=filelen/4;
 
3442
+           if(lseek(fd, jumpFalseLoc, SEEK_SET) == -1)
 
3443
+               return -1;
 
3444
+           if(write_int(fd,jumpto) == -1)
 
3445
+               return -1;
 
3446
+           if(lseek(fd,filelen,SEEK_SET) == -1)
 
3447
+               return -1;
 
3448
+           
 
3449
+           /* there is an else case */
 
3450
+           if(bc->data[codep+2].value != -1) {
 
3451
+               /* spew the else code */
 
3452
+               elsedist = bc_action_emit(fd, bc->data[codep+1].value,
 
3453
+                                        bc->data[codep+2].value, bc,
 
3454
+                                        filelen);
 
3455
+       
 
3456
+               filelen+=elsedist;
 
3457
+               
 
3458
+               /*put jump to the end of the else code*/
 
3459
+               jumpto=filelen/4;
 
3460
+               if(lseek(fd, jumpEndLoc, SEEK_SET) == -1)
 
3461
+                   return -1;
 
3462
+               if(write_int(fd,jumpto) == -1)
 
3463
+                   return -1;
 
3464
+               if(lseek(fd,filelen,SEEK_SET) == -1)
 
3465
+                   return -1;
 
3466
+               
 
3467
+               codep = bc->data[codep+2].value;
 
3468
+           } else {
 
3469
+               codep = bc->data[codep+1].value;
 
3470
+           }
 
3471
+           
 
3472
+           break;
 
3473
+       }
 
3474
+       
 
3475
+       case B_REJECT:
 
3476
+       case B_FILEINTO:
 
3477
+       case B_REDIRECT:
 
3478
+           /*just a string*/
 
3479
+           len = bc->data[codep++].len;
 
3480
+           if(write_int(fd,len) == -1)
 
3481
+               return -1;
 
3482
+
 
3483
+           filelen+=sizeof(int);
 
3484
+           
 
3485
+           if(write(fd,bc->data[codep++].str,len) == -1)
 
3486
+               return -1;
 
3487
+           
 
3488
+           ret = align_string(fd, len);
 
3489
+           if(ret == -1)
 
3490
+               return -1;
 
3491
+
 
3492
+           filelen += len + ret;
 
3493
+           
 
3494
+           break; 
 
3495
+
 
3496
+       case B_SETFLAG:
 
3497
+       case B_ADDFLAG:
 
3498
+       case B_REMOVEFLAG:
 
3499
+           /* Dump just a stringlist */
 
3500
+           ret = bc_stringlist_emit(fd, &codep, bc);
 
3501
+           if(ret < 0)
 
3502
+               return -1;
 
3503
+           filelen += ret;
 
3504
+           break;
 
3505
+           
 
3506
+       case B_NOTIFY:
 
3507
+           /* method string, id string, options string list,
 
3508
+              priotity, Message String */
 
3509
+           /*method and id*/
 
3510
+           for(i=0; i<2; i++) {
 
3511
+               len = bc->data[codep++].len;
 
3512
+               if(write_int(fd,len) == -1)
 
3513
+                   return -1;
 
3514
+               filelen += sizeof(int);
 
3515
+               if(len == -1)
 
3516
+               {
 
3517
+                    /* this will probably only happen for the id */
 
3518
+                   /* this is a nil string */
 
3519
+                   /* skip the null pointer and make up for it 
 
3520
+                    * by adjusting the offset */
 
3521
+                   codep++;
 
3522
+               }
 
3523
+               else
 
3524
+               {       
 
3525
+                   if(write(fd,bc->data[codep++].str,len) == -1)
 
3526
+                       return -1;
 
3527
+                   
 
3528
+                   ret = align_string(fd, len);
 
3529
+                   if(ret == -1)
 
3530
+                       return -1;
 
3531
+                   
 
3532
+                   filelen += len + ret;
 
3533
+               }
 
3534
+               
 
3535
+           }
 
3536
+           /*options */
 
3537
+           ret = bc_stringlist_emit(fd, &codep, bc);
 
3538
+           if(ret < 0)
 
3539
+               return -1;
 
3540
+           filelen+=ret;
 
3541
+           
 
3542
+           /*priority*/
 
3543
+           if(write_int(fd, bc->data[codep].value) == -1)
 
3544
+               return -1;
 
3545
+           codep++;
 
3546
+           filelen += sizeof(int);
 
3547
+           
 
3548
+           len = bc->data[codep++].len;
 
3549
+           if(write_int(fd,len) == -1)
 
3550
+               return -1;
 
3551
+           filelen += sizeof(int);
 
3552
+           
 
3553
+           if(write(fd,bc->data[codep++].str,len) == -1)
 
3554
+               return -1;
 
3555
+           
 
3556
+           ret = align_string(fd, len);
 
3557
+           if(ret == -1) return -1;
 
3558
+           
 
3559
+           filelen += len + ret;
 
3560
+           break;
 
3561
+
 
3562
+               
 
3563
+       case B_DENOTIFY:
 
3564
+           /* priority num,comptype  num,relat num, comp string*/ 
 
3565
+
 
3566
+           /* priority*/
 
3567
+           if(write_int(fd, bc->data[codep].value) == -1)
 
3568
+               return -1;
 
3569
+           filelen += sizeof(int);
 
3570
+           codep++;
 
3571
+           /* comptype */
 
3572
+           if(write_int(fd, bc->data[codep].value) == -1)
 
3573
+               return -1;
 
3574
+           filelen += sizeof(int);
 
3575
+           codep++;
 
3576
+           /* relational*/
 
3577
+           if(write_int(fd, bc->data[codep].value) == -1)
 
3578
+               return -1;
 
3579
+           filelen += sizeof(int);
 
3580
+           codep++;
 
3581
+           /* comp string*/
 
3582
+           
 
3583
+           len = bc->data[codep++].len;
 
3584
+           if(write_int(fd,len) == -1)
 
3585
+               return -1;
 
3586
+           filelen += sizeof(int);
 
3587
+           
 
3588
+           if(len == -1)
 
3589
+           {
 
3590
+               /* this is a nil string */
 
3591
+               /* skip the null pointer and make up for it 
 
3592
+                * by adjusting the offset */
 
3593
+               codep++;
 
3594
+           }
 
3595
+           else
 
3596
+           {
 
3597
+               if(write(fd,bc->data[codep++].str,len) == -1)
 
3598
+                   return -1;
 
3599
+               
 
3600
+               ret = align_string(fd, len);
 
3601
+               if(ret == -1) return -1;
 
3602
+               
 
3603
+               filelen += len + ret;
 
3604
+           }
 
3605
+                   break;
 
3606
+       case B_VACATION:
 
3607
+           /* Address list, Subject String, Message String,
 
3608
+              Days (word), Mime (word) */
 
3609
+          
 
3610
+               /*new code-this might be broken*/
 
3611
+           ret = bc_stringlist_emit(fd, &codep, bc);
 
3612
+           if(ret < 0) return -1;
 
3613
+           filelen += ret;
 
3614
+           /*end of new code*/
 
3615
+
 
3616
+           for(i=0; i<2; i++) {/*writing strings*/
 
3617
+
 
3618
+               /*write length of string*/
 
3619
+               len = bc->data[codep++].len;
 
3620
+               if(write_int(fd,len) == -1)
 
3621
+                   return -1;
 
3622
+               filelen += sizeof(int);
 
3623
+                   
 
3624
+               if(len == -1)
 
3625
+               {
 
3626
+                   /* this is a nil string */
 
3627
+                   /* skip the null pointer and make up for it 
 
3628
+                    * by adjusting the offset */
 
3629
+                   codep++;
 
3630
+               }
 
3631
+               else
 
3632
+               {
 
3633
+                   /*write string*/
 
3634
+                   if(write(fd,bc->data[codep++].str,len) == -1)
 
3635
+                       return -1;
 
3636
+                   
 
3637
+                   ret = align_string(fd, len);
 
3638
+                   if(ret == -1) return -1;
 
3639
+                   
 
3640
+                   filelen += len + ret;
 
3641
+               }
 
3642
+               
 
3643
+           }
 
3644
+           /* Days*/
 
3645
+           if(write_int(fd,bc->data[codep].value) == -1)
 
3646
+               return -1;
 
3647
+           codep++;
 
3648
+           filelen += sizeof(int);
 
3649
+            /*Mime */
 
3650
+           if(write_int(fd,bc->data[codep].value) == -1)
 
3651
+               return -1;
 
3652
+           codep++;
 
3653
+           filelen += sizeof(int);
 
3654
+           
 
3655
+           break;
 
3656
+       case B_NULL:
 
3657
+       case B_STOP:
 
3658
+       case B_DISCARD:
 
3659
+       case B_KEEP:
 
3660
+       case B_MARK:
 
3661
+       case B_UNMARK:
 
3662
+           /* No Parameters! */
 
3663
+           break;
 
3664
+
 
3665
+       default:
 
3666
+           /* Unknown opcode? */
 
3667
+           return -1;
 
3668
+       }
 
3669
+    }
 
3670
+    return filelen - start_filelen;
 
3671
+}
 
3672
+
 
3673
+/* spew the bytecode to disk */
 
3674
+int sieve_emit_bytecode(int fd, bytecode_info_t *bc)  
 
3675
+{
 
3676
+    /* First output version number (4 bytes) */
 
3677
+    int data = BYTECODE_VERSION;
 
3678
+
 
3679
+    /*this is a string, so it is happy*/
 
3680
+    if(write(fd, BYTECODE_MAGIC, BYTECODE_MAGIC_LEN) == -1)
 
3681
+       return -1;
 
3682
+
 
3683
+    if(write_int(fd, data) == -1) return -1;
 
3684
+
 
3685
+#if DUMPCODE
 
3686
+    dump(bc);
 
3687
+#endif
 
3688
+
 
3689
+    /*the sizeof(int) is to account for the version # at the begining*/
 
3690
+    return bc_action_emit(fd, 0, bc->scriptend, bc, sizeof(int) + BYTECODE_MAGIC_LEN);
 
3691
+}
 
3692
+
 
3693
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/bc_eval.c
 
3694
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
3695
+++ b/src/lib-sieve/cmu/libsieve/bc_eval.c      Sun May 04 16:00:59 2008 +0200
 
3696
@@ -0,0 +1,1146 @@
 
3697
+/* bc_eval.c - evaluate the bytecode
 
3698
+ * $Id$
 
3699
+ */
 
3700
+/***********************************************************
 
3701
+        Copyright 2001 by Carnegie Mellon University
 
3702
+
 
3703
+                      All Rights Reserved
 
3704
+
 
3705
+Permission to use, copy, modify, and distribute this software and its
 
3706
+documentation for any purpose and without fee is hereby granted,
 
3707
+provided that the above copyright notice appear in all copies and that
 
3708
+both that copyright notice and this permission notice appear in
 
3709
+supporting documentation, and that the name of Carnegie Mellon
 
3710
+University not be used in advertising or publicity pertaining to
 
3711
+distribution of the software without specific, written prior
 
3712
+permission.
 
3713
+
 
3714
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
3715
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
3716
+FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
 
3717
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
3718
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
3719
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 
3720
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
3721
+******************************************************************/
 
3722
+
 
3723
+#ifdef HAVE_CONFIG_H
 
3724
+#include <config.h>
 
3725
+#endif
 
3726
+
 
3727
+#include "sieve_interface.h"
 
3728
+#include "interp.h"
 
3729
+#include "message.h"
 
3730
+
 
3731
+#include "bytecode.h"
 
3732
+
 
3733
+#include "xmalloc.h"
 
3734
+
 
3735
+#include <string.h>
 
3736
+#include <ctype.h>
 
3737
+
 
3738
+/**************************************************************************/
 
3739
+/**************************************************************************/
 
3740
+/**************************************************************************/
 
3741
+/**************************EXECUTING BYTECODE******************************/
 
3742
+/**************************************************************************/
 
3743
+/**************************************************************************/
 
3744
+/**************************************************************************/
 
3745
+/**************************************************************************/
 
3746
+
 
3747
+/* Given a bytecode_input_t at the beginning of a string (the len block),
 
3748
+ * return the string, the length, and the bytecode index of the NEXT
 
3749
+ * item */
 
3750
+int unwrap_string(bytecode_input_t *bc, int pos, const char **str, int *len)
 
3751
+{
 
3752
+    int local_len = ntohl(bc[pos].value);
 
3753
+
 
3754
+    pos++;
 
3755
+    
 
3756
+    if(local_len == -1) {
 
3757
+       /* -1 length indicates NULL */
 
3758
+       *str = NULL;
 
3759
+    } else {
 
3760
+       /* This cast is ugly, but necessary */
 
3761
+       *str = (const char *)&bc[pos].str;
 
3762
+       
 
3763
+       /* Compute the next index */
 
3764
+       pos += ((ROUNDUP(local_len+1))/sizeof(bytecode_input_t));
 
3765
+    }
 
3766
+    
 
3767
+    if(len) *len = local_len;
 
3768
+    
 
3769
+    return pos;
 
3770
+}
 
3771
+
 
3772
+
 
3773
+/* this is used by notify to pass the options list to do_notify
 
3774
+ * do_notify needs null-terminated (char *)[],
 
3775
+ *  we have a stringlist, the beginning of which is pointed at by pos */
 
3776
+static const char ** bc_makeArray(bytecode_input_t *bc, int *pos)
 
3777
+{
 
3778
+    int i;
 
3779
+    const char** array;
 
3780
+    int len = ntohl(bc[*pos].value);
 
3781
+
 
3782
+    (*pos)+=2; /* Skip # Values and Total Byte Length */
 
3783
+  
 
3784
+    array=(const char **)xmalloc((len+1) * sizeof(char *));
 
3785
+
 
3786
+    for (i=0; i<len; i++) {
 
3787
+       *pos = unwrap_string(bc, *pos, &(array[i]), NULL);
 
3788
+    }
 
3789
+
 
3790
+    array[i] = NULL;
 
3791
+  
 
3792
+    return array;
 
3793
+}
 
3794
+
 
3795
+/* Compile a regular expression for use during parsing */
 
3796
+static regex_t * bc_compile_regex(const char *s, int ctag,
 
3797
+                                 char *errmsg, size_t errsiz)
 
3798
+{
 
3799
+    int ret;
 
3800
+    regex_t *reg = (regex_t *) xmalloc(sizeof(regex_t));
 
3801
+    
 
3802
+    if ( (ret=regcomp(reg, s, ctag)) != 0)
 
3803
+    {
 
3804
+       (void) regerror(ret, reg, errmsg, errsiz);
 
3805
+       free(reg);
 
3806
+       return NULL;
 
3807
+    }
 
3808
+    return reg;
 
3809
+}
 
3810
+
 
3811
+/* Determine if addr is a system address */
 
3812
+static int sysaddr(const char *addr)
 
3813
+{
 
3814
+    if (!strncasecmp(addr, "MAILER-DAEMON", 13))
 
3815
+       return 1;
 
3816
+
 
3817
+    if (!strncasecmp(addr, "LISTSERV", 8))
 
3818
+       return 1;
 
3819
+
 
3820
+    if (!strncasecmp(addr, "majordomo", 9))
 
3821
+       return 1;
 
3822
+
 
3823
+    if (strstr(addr, "-request"))
 
3824
+       return 1;
 
3825
+
 
3826
+    if (!strncmp(addr, "owner-", 6))
 
3827
+       return 1;
 
3828
+
 
3829
+    return 0;
 
3830
+}
 
3831
+
 
3832
+/* look for myaddr and myaddrs in the body of a header - return the match */
 
3833
+static char* look_for_me(char *myaddr, int numaddresses,
 
3834
+                              bytecode_input_t *bc, int i, const char **body)
 
3835
+{
 
3836
+    char *found = NULL;
 
3837
+    int l;
 
3838
+    int curra,x ;
 
3839
+
 
3840
+    /* loop through each TO header */
 
3841
+    for (l = 0; body[l] != NULL && !found; l++) {
 
3842
+       void *data = NULL, *marker = NULL;
 
3843
+       char *addr;
 
3844
+       
 
3845
+       parse_address(body[l], &data, &marker);
 
3846
+
 
3847
+       /* loop through each address in the header */
 
3848
+       while (!found &&
 
3849
+              ((addr = get_address(ADDRESS_ALL,&data, &marker, 1))!= NULL)) {
 
3850
+
 
3851
+           if (!strcasecmp(addr, myaddr)) {
 
3852
+               found = xstrdup(myaddr);
 
3853
+               break;
 
3854
+           }
 
3855
+
 
3856
+           curra=i;
 
3857
+
 
3858
+           for(x=0; x<numaddresses; x++)
 
3859
+           {
 
3860
+               void *altdata = NULL, *altmarker = NULL;
 
3861
+               char *altaddr;
 
3862
+               const char *str;
 
3863
+
 
3864
+               curra = unwrap_string(bc, curra, &str, NULL);
 
3865
+               
 
3866
+               /* is this address one of my addresses? */
 
3867
+               parse_address(str, &altdata, &altmarker);
 
3868
+
 
3869
+               altaddr = get_address(ADDRESS_ALL, &altdata, &altmarker, 1);
 
3870
+
 
3871
+               if (!strcasecmp(addr,altaddr)) {
 
3872
+                   found=xstrdup(str);
 
3873
+                   break;
 
3874
+               }
 
3875
+
 
3876
+               free_address(&altdata, &altmarker);
 
3877
+           }
 
3878
+
 
3879
+       }
 
3880
+       free_address(&data, &marker);
 
3881
+    }
 
3882
+
 
3883
+    return found;
 
3884
+}
 
3885
 
3886
+/* Determine if we should respond to a vacation message */
 
3887
+static int shouldRespond(void * m, sieve_interp_t *interp,
 
3888
+                        int numaddresses, bytecode_input_t* bc,
 
3889
+                        int i, char **from, char **to)
 
3890
+{
 
3891
+    const char **body;
 
3892
+    char buf[128];
 
3893
+    char *myaddr = NULL;
 
3894
+    int l = SIEVE_OK;
 
3895
+    void *data = NULL, *marker = NULL;
 
3896
+    char *tmp;
 
3897
+    int curra, x;
 
3898
+    char *found=NULL;
 
3899
+    char *reply_to=NULL;
 
3900
+  
 
3901
+    /* is there an Auto-Submitted keyword other than "no"? */
 
3902
+    strcpy(buf, "auto-submitted");
 
3903
+    if (interp->getheader(m, buf, &body) == SIEVE_OK) {
 
3904
+       /* we don't deal with comments, etc. here */
 
3905
+       /* skip leading white-space */
 
3906
+       while (*body[0] && isspace((int) *body[0])) body[0]++;
 
3907
+       if (strcasecmp(body[0], "no")) l = SIEVE_DONE;
 
3908
+    }
 
3909
+
 
3910
+    /* is there a Precedence keyword of "junk | bulk | list"? */
 
3911
+    strcpy(buf, "precedence");
 
3912
+    if (interp->getheader(m, buf, &body) == SIEVE_OK) {
 
3913
+       /* we don't deal with comments, etc. here */
 
3914
+       /* skip leading white-space */
 
3915
+       while (*body[0] && isspace((int) *body[0])) body[0]++;
 
3916
+       if (!strcasecmp(body[0], "junk") ||
 
3917
+           !strcasecmp(body[0], "bulk") ||
 
3918
+           !strcasecmp(body[0], "list"))
 
3919
+           l = SIEVE_DONE;
 
3920
+    }
 
3921
+
 
3922
+    /* Note: the domain-part of all addresses are canonicalized */
 
3923
+    /* grab my address from the envelope */
 
3924
+    if (l == SIEVE_OK) {
 
3925
+       strcpy(buf, "to");
 
3926
+       l = interp->getenvelope(m, buf, &body);
 
3927
+       
 
3928
+       if (body[0]) {  
 
3929
+           parse_address(body[0], &data, &marker);
 
3930
+           tmp = get_address(ADDRESS_ALL, &data, &marker, 1);
 
3931
+           myaddr = (tmp != NULL) ? xstrdup(tmp) : NULL;
 
3932
+           free_address(&data, &marker);
 
3933
+       }  
 
3934
+    }  
 
3935
+  
 
3936
+    if (l == SIEVE_OK) {
 
3937
+       strcpy(buf, "from");
 
3938
+       l = interp->getenvelope(m, buf, &body);
 
3939
+    }
 
3940
+    if (l == SIEVE_OK && body[0]) {
 
3941
+       /* we have to parse this address & decide whether we
 
3942
+          want to respond to it */
 
3943
+       parse_address(body[0], &data, &marker);
 
3944
+       tmp = get_address(ADDRESS_ALL, &data, &marker, 1);
 
3945
+       reply_to = (tmp != NULL) ? xstrdup(tmp) : NULL;
 
3946
+       free_address(&data, &marker);
 
3947
+
 
3948
+       /* first, is there a reply-to address? */
 
3949
+       if (reply_to == NULL) {
 
3950
+           l = SIEVE_DONE;
 
3951
+       }
 
3952
+    
 
3953
+       /* first, is it from me? */
 
3954
+       if (l == SIEVE_OK && !strcmp(myaddr, reply_to)) {
 
3955
+           l = SIEVE_DONE;
 
3956
+       }
 
3957
+   
 
3958
+       /* ok, is it any of the other addresses i've
 
3959
+          specified? */
 
3960
+       if (l == SIEVE_OK)
 
3961
+       {
 
3962
+           curra=i;
 
3963
+           for(x=0; x<numaddresses; x++) {
 
3964
+               const char *address;
 
3965
+
 
3966
+               curra = unwrap_string(bc, curra, &address, NULL);
 
3967
+               
 
3968
+               if (!strcmp(address, reply_to))
 
3969
+                   l=SIEVE_DONE;
 
3970
+           }
 
3971
+       }
 
3972
+   
 
3973
+       /* ok, is it a system address? */
 
3974
+       if (l == SIEVE_OK && sysaddr(reply_to)) {
 
3975
+           l = SIEVE_DONE;
 
3976
+       }
 
3977
+    }
 
3978
+    if (l == SIEVE_OK) {
 
3979
+       /* ok, we're willing to respond to the sender.
 
3980
+          but is this message to me?  that is, is my address
 
3981
+          in the TO, CC or BCC fields? */
 
3982
+       if (strcpy(buf, "to"), 
 
3983
+           interp->getheader(m, buf, &body) == SIEVE_OK)
 
3984
+           found = look_for_me(myaddr, numaddresses ,bc, i, body);
 
3985
+       if (!found && (strcpy(buf, "cc"),
 
3986
+                      (interp->getheader(m, buf, &body) == SIEVE_OK)))
 
3987
+           found = look_for_me(myaddr, numaddresses, bc, i, body);
 
3988
+       if (!found && (strcpy(buf, "bcc"),
 
3989
+                      (interp->getheader(m, buf, &body) == SIEVE_OK)))
 
3990
+           found = look_for_me(myaddr, numaddresses, bc, i, body);
 
3991
+       if (!found)
 
3992
+           l = SIEVE_DONE;
 
3993
+    }
 
3994
+    /* ok, ok, if we got here maybe we should reply */
 
3995
+    if (myaddr) free(myaddr);
 
3996
+    *from=found;
 
3997
+    *to=reply_to;
 
3998
+    return l;
 
3999
+}
 
4000
+
 
4001
+/* Evaluate a bytecode test */
 
4002
+static int eval_bc_test(sieve_interp_t *interp, void* m,
 
4003
+                       bytecode_input_t * bc, int * ip)
 
4004
+{
 
4005
+    int res=0; 
 
4006
+    int i=*ip;
 
4007
+    int x,y,z;/* loop variable */
 
4008
+    int list_len; /* for allof/anyof/exists */
 
4009
+    int list_end; /* for allof/anyof/exists */
 
4010
+    int address=0;/*to differentiate between address and envelope*/
 
4011
+    comparator_t * comp=NULL;
 
4012
+    void * comprock=NULL;
 
4013
+    int op= ntohl(bc[i].op);
 
4014
+    
 
4015
+    switch(op)
 
4016
+    {
 
4017
+    case BC_FALSE:
 
4018
+       res=0; i++; break;
 
4019
+
 
4020
+    case BC_TRUE:
 
4021
+       res=1; i++; break;
 
4022
+
 
4023
+    case BC_NOT:/*2*/
 
4024
+       i+=1;
 
4025
+       res = eval_bc_test(interp,m, bc, &i);
 
4026
+       if(res >= 0) res = !res; /* Only invert in non-error case */
 
4027
+       break;
 
4028
+
 
4029
+    case BC_EXISTS:/*3*/
 
4030
+    {
 
4031
+       int headersi=i+1;
 
4032
+       const char** val;
 
4033
+       int currh;
 
4034
+
 
4035
+       res=1;
 
4036
+
 
4037
+       list_len=ntohl(bc[headersi].len);
 
4038
+       list_end=ntohl(bc[headersi+1].value)/4;
 
4039
+
 
4040
+       currh=headersi+2;
 
4041
+
 
4042
+       for(x=0; x<list_len && res; x++)
 
4043
+       {
 
4044
+           const char *str;
 
4045
+
 
4046
+           currh = unwrap_string(bc, currh, &str, NULL);
 
4047
+           
 
4048
+           if(interp->getheader(m,str, &val) != SIEVE_OK)
 
4049
+               res = 0;
 
4050
+       }
 
4051
+
 
4052
+       i=list_end; /* adjust for short-circuit */
 
4053
+       break;
 
4054
+    }
 
4055
+    case BC_SIZE:/*4*/
 
4056
+    {
 
4057
+       int s;
 
4058
+       int sizevar=ntohl(bc[i+1].value);
 
4059
+       int x=ntohl(bc[i+2].value);
 
4060
+       
 
4061
+       if (interp->getsize(m, &s) != SIEVE_OK)
 
4062
+           break;
 
4063
+       
 
4064
+       if (sizevar ==B_OVER) {
 
4065
+           /* over */
 
4066
+           res= s > x;
 
4067
+       } else {
 
4068
+            /* under */
 
4069
+           res= s < x;
 
4070
+       }
 
4071
+       i+=3;
 
4072
+       break;
 
4073
+    }
 
4074
+    case BC_ANYOF:/*5*/
 
4075
+       res = 0;
 
4076
+       list_len=ntohl(bc[i+1].len);
 
4077
+       list_end=ntohl(bc[i+2].len)/4;
 
4078
+       i+=3;
 
4079
+
 
4080
+       /* need to process all of them, to ensure our instruction pointer stays
 
4081
+        * in the right place */
 
4082
+       for (x=0; x<list_len && !res; x++) { 
 
4083
+           int tmp;
 
4084
+           tmp = eval_bc_test(interp,m,bc,&i);
 
4085
+           if(tmp < 0) {
 
4086
+               res = tmp;
 
4087
+               break;
 
4088
+           }
 
4089
+           res = res || tmp;
 
4090
+       }
 
4091
+
 
4092
+       i = list_end; /* handle short-circuting */
 
4093
+
 
4094
+       break; 
 
4095
+    case BC_ALLOF:/*6*/ 
 
4096
+        res = 1;     
 
4097
+       list_len=ntohl(bc[i+1].len);
 
4098
+       list_end=ntohl(bc[i+2].len)/4;
 
4099
+       i+=3;
 
4100
+
 
4101
+       /* return 1 unless you find one that isn't true, then return 0 */
 
4102
+       for (x=0; x<list_len && res; x++) {
 
4103
+           int tmp;
 
4104
+           tmp = eval_bc_test(interp,m,bc,&i);
 
4105
+           if(tmp < 0) {
 
4106
+               res = tmp;
 
4107
+               break;
 
4108
+           }
 
4109
+           res = res && tmp; 
 
4110
+       }
 
4111
+
 
4112
+       i = list_end; /* handle short-circuiting */
 
4113
+       
 
4114
+       break;
 
4115
+    case BC_ADDRESS:/*7*/
 
4116
+       address=1;
 
4117
+       /* fall through */
 
4118
+    case BC_ENVELOPE:/*8*/
 
4119
+    {
 
4120
+       const char ** val;
 
4121
+       void * data=NULL;
 
4122
+       void * marker=NULL;
 
4123
+       char * addr;
 
4124
+       int addrpart=ADDRESS_ALL;/* XXX correct default behavior?*/
 
4125
+
 
4126
+       int headersi=i+5;/* the i value for the begining of the headers */
 
4127
+       int datai=(ntohl(bc[headersi+1].value)/4);
 
4128
+
 
4129
+       int numheaders=ntohl(bc[headersi].len);
 
4130
+       int numdata=ntohl(bc[datai].len);
 
4131
+
 
4132
+       int currh, currd; /* current header, current data */
 
4133
+
 
4134
+       int match=ntohl(bc[i+1].value);
 
4135
+       int relation=ntohl(bc[i+2].value);
 
4136
+       int comparator=ntohl(bc[i+3].value);
 
4137
+       int apart=ntohl(bc[i+4].value);
 
4138
+       int count=0;
 
4139
+       char scount[3];
 
4140
+       int isReg = (match==B_REGEX);
 
4141
+       int ctag = 0;
 
4142
+       regex_t *reg;
 
4143
+       char errbuf[100]; /* Basically unused, as regexps are tested at compile */
 
4144
+
 
4145
+       /* set up variables needed for compiling regex */
 
4146
+       if (isReg)
 
4147
+       {
 
4148
+           if (comparator== B_ASCIICASEMAP)
 
4149
+           {
 
4150
+               ctag = REG_EXTENDED | REG_NOSUB | REG_ICASE;
 
4151
+           }
 
4152
+           else
 
4153
+           {
 
4154
+               ctag = REG_EXTENDED | REG_NOSUB;
 
4155
+           }
 
4156
+       }
 
4157
+
 
4158
+       /*find the correct comparator fcn*/
 
4159
+       comp = lookup_comp(comparator, match, relation, &comprock);
 
4160
+
 
4161
+       if(!comp) {
 
4162
+           res = SIEVE_RUN_ERROR;
 
4163
+           break;
 
4164
+       }
 
4165
+       
 
4166
+       /*find the part of the address that we want*/
 
4167
+       switch(apart)
 
4168
+       {
 
4169
+       case B_ALL:
 
4170
+           addrpart = ADDRESS_ALL; break;
 
4171
+       case B_LOCALPART:
 
4172
+           addrpart = ADDRESS_LOCALPART; break;
 
4173
+       case B_DOMAIN:
 
4174
+           addrpart = ADDRESS_DOMAIN; break;
 
4175
+       case B_USER:
 
4176
+           addrpart = ADDRESS_USER; break;
 
4177
+       case B_DETAIL:
 
4178
+           addrpart = ADDRESS_DETAIL; break;
 
4179
+       default:
 
4180
+           /* this shouldn't happen with correcct bytecode */
 
4181
+           res = SIEVE_RUN_ERROR;
 
4182
+       }
 
4183
+
 
4184
+       if(res == SIEVE_RUN_ERROR) break;
 
4185
+
 
4186
+       /*loop through all the headers*/
 
4187
+       currh=headersi+2;
 
4188
+#if VERBOSE
 
4189
+       printf("about to process %d headers\n", numheaders);
 
4190
+#endif
 
4191
+       for (x=0; x<numheaders && !res; x++)
 
4192
+       {
 
4193
+           const char *this_header;
 
4194
+
 
4195
+           currh = unwrap_string(bc, currh, &this_header, NULL);
 
4196
+           
 
4197
+           /* Try the next string if we don't have this one */
 
4198
+           if(address) {
 
4199
+               /* Header */
 
4200
+               if(interp->getheader(m, this_header, &val) != SIEVE_OK)
 
4201
+                   continue;
 
4202
+#if VERBOSE
 
4203
+                printf(" [%d] header %s is %s\n", x, this_header, val[0]);
 
4204
+#endif
 
4205
+           } else {
 
4206
+               /* Envelope */
 
4207
+               if(interp->getenvelope(m, this_header, &val) != SIEVE_OK)
 
4208
+                   continue;
 
4209
+           }
 
4210
+       
 
4211
+           /*header exists, now to test it*/
 
4212
+           /*search through all the headers that match*/
 
4213
+           
 
4214
+           for (y=0; val[y]!=NULL && !res; y++) {
 
4215
+               
 
4216
+#if VERBOSE
 
4217
+               printf("about to parse %s\n", val[y]);
 
4218
+#endif
 
4219
+                   
 
4220
+               if (parse_address(val[y], &data, &marker)!=SIEVE_OK) 
 
4221
+                   return 0;
 
4222
+                   
 
4223
+               while (!res &&
 
4224
+                      (addr = get_address(addrpart, &data, &marker, 0))) {
 
4225
+#if VERBOSE
 
4226
+                   printf("working addr %s\n", (addr ? addr : "[nil]"));
 
4227
+#endif
 
4228
+                       
 
4229
+                   if (match == B_COUNT) {
 
4230
+                       count++;
 
4231
+                   } else {
 
4232
+                       /*search through all the data*/ 
 
4233
+                       currd=datai+2;
 
4234
+                       for (z=0; z<numdata && !res; z++)
 
4235
+                       {
 
4236
+                           const char *data_val;
 
4237
+                           
 
4238
+                           currd = unwrap_string(bc, currd, &data_val, NULL);
 
4239
+
 
4240
+                           if (isReg) {
 
4241
+                               reg = bc_compile_regex(data_val, ctag,
 
4242
+                                                      errbuf, sizeof(errbuf));
 
4243
+                               if (!reg) {
 
4244
+                                   /* Oops */
 
4245
+                                   res=-1;
 
4246
+                                   goto alldone;
 
4247
+                               }
 
4248
+
 
4249
+                               res |= comp(val[y], (const char *)reg,
 
4250
+                                           comprock);
 
4251
+                               free(reg);
 
4252
+                           } else {
 
4253
+#if VERBOSE
 
4254
+                               printf("%s compared to %s(from script)\n",
 
4255
+                                      addr, data_val);
 
4256
+#endif 
 
4257
+                               res |= comp(addr, data_val, comprock);
 
4258
+                           }
 
4259
+                       } /* For each data */
 
4260
+                   }
 
4261
+               } /* For each address */
 
4262
+
 
4263
+               free_address(&data, &marker);
 
4264
+           }/* For each message header */
 
4265
+           
 
4266
+#if VERBOSE
 
4267
+           printf("end of loop, res is %d, x is %d (%d)\n", res, x, numheaders);
 
4268
+#endif     
 
4269
+       } /* For each script header */
 
4270
+     
 
4271
+       if  (match == B_COUNT)
 
4272
+       {
 
4273
+           sprintf(scount, "%u", count);
 
4274
+           /* search through all the data */ 
 
4275
+           currd=datai+2;
 
4276
+           for (z=0; z<numdata && !res; z++)
 
4277
+           {
 
4278
+               const char *data_val;
 
4279
+               
 
4280
+               currd = unwrap_string(bc, currd, &data_val, NULL);
 
4281
+
 
4282
+               res |= comp(scount, data_val, comprock);
 
4283
+           }
 
4284
+       }
 
4285
+
 
4286
+       /* Update IP */
 
4287
+       i=(ntohl(bc[datai+1].value)/4);
 
4288
+       
 
4289
+       break;
 
4290
+    }
 
4291
+    case BC_HEADER:/*9*/
 
4292
+    {
 
4293
+       const char** val;
 
4294
+
 
4295
+       int headersi=i+4;/*the i value for the begining of hte headers*/
 
4296
+       int datai=(ntohl(bc[headersi+1].value)/4);
 
4297
+
 
4298
+       int numheaders=ntohl(bc[headersi].len);
 
4299
+       int numdata=ntohl(bc[datai].len);
 
4300
+
 
4301
+       int currh, currd; /*current header, current data*/
 
4302
+
 
4303
+       int match=ntohl(bc[i+1].value);
 
4304
+       int relation=ntohl(bc[i+2].value);
 
4305
+       int comparator=ntohl(bc[i+3].value);
 
4306
+       int count=0;    
 
4307
+       char scount[3];
 
4308
+       int isReg = (match==B_REGEX);
 
4309
+       int ctag = 0;
 
4310
+       regex_t *reg;
 
4311
+       char errbuf[100]; /* Basically unused, regexps tested at compile */ 
 
4312
+
 
4313
+       /* set up variables needed for compiling regex */
 
4314
+       if (isReg)
 
4315
+       {
 
4316
+           if (comparator== B_ASCIICASEMAP)
 
4317
+           {
 
4318
+               ctag= REG_EXTENDED | REG_NOSUB | REG_ICASE;
 
4319
+           }
 
4320
+           else
 
4321
+           {
 
4322
+               ctag= REG_EXTENDED | REG_NOSUB;
 
4323
+           }
 
4324
+     
 
4325
+       }
 
4326
+       
 
4327
+       /*find the correct comparator fcn*/
 
4328
+       comp=lookup_comp(comparator, match, relation, &comprock);
 
4329
+
 
4330
+       if(!comp) {
 
4331
+           res = SIEVE_RUN_ERROR;
 
4332
+           break;
 
4333
+       }
 
4334
+
 
4335
+       /*search through all the flags for the header*/
 
4336
+       currh=headersi+2;
 
4337
+       for(x=0; x<numheaders && !res; x++)
 
4338
+       {
 
4339
+           const char *this_header;
 
4340
+           
 
4341
+           currh = unwrap_string(bc, currh, &this_header, NULL);
 
4342
+          
 
4343
+           if(interp->getheader(m, this_header, &val) != SIEVE_OK) {
 
4344
+               continue; /*this header does not exist, search the next*/ 
 
4345
+           }
 
4346
+#if VERBOSE
 
4347
+           printf ("val %s %s %s\n", val[0], val[1], val[2]);
 
4348
+#endif
 
4349
+           
 
4350
+           /* search through all the headers that match */
 
4351
+           
 
4352
+           for (y=0; val[y]!=NULL && !res; y++)
 
4353
+           {
 
4354
+               if  (match == B_COUNT) {
 
4355
+                   count++;
 
4356
+               } else {
 
4357
+                   /*search through all the data*/ 
 
4358
+                   currd=datai+2;
 
4359
+                   for (z=0; z<numdata && !res; z++)
 
4360
+                   {
 
4361
+                       const char *data_val;
 
4362
+                       
 
4363
+                       currd = unwrap_string(bc, currd, &data_val, NULL);
 
4364
+                       
 
4365
+                       if (isReg) {
 
4366
+                           reg= bc_compile_regex(data_val, ctag, errbuf,
 
4367
+                                                 sizeof(errbuf));
 
4368
+                           if (!reg)
 
4369
+                           {
 
4370
+                               /* Oops */
 
4371
+                               res=-1;
 
4372
+                               goto alldone;
 
4373
+                           }
 
4374
+                           
 
4375
+                           res |= comp(val[y], (const char *)reg,
 
4376
+                                       comprock);
 
4377
+                           free(reg);
 
4378
+                       } else {
 
4379
+                           res |= comp(val[y], data_val, comprock);
 
4380
+                       }
 
4381
+                   }
 
4382
+               }
 
4383
+           }
 
4384
+       }
 
4385
+       
 
4386
+       if  (match == B_COUNT )
 
4387
+       {
 
4388
+           sprintf(scount, "%u", count);
 
4389
+           /*search through all the data*/ 
 
4390
+           currd=datai+2;
 
4391
+           for (z=0; z<numdata && !res; z++)
 
4392
+           {   
 
4393
+               const char *data_val;
 
4394
+                       
 
4395
+               currd = unwrap_string(bc, currd, &data_val, NULL);
 
4396
+#if VERBOSE
 
4397
+               printf("%d, %s \n", count, data_val);
 
4398
+#endif
 
4399
+               res |= comp(scount, data_val, comprock);
 
4400
+           }
 
4401
+             
 
4402
+       }
 
4403
+
 
4404
+       /* Update IP */
 
4405
+       i=(ntohl(bc[datai+1].value)/4);
 
4406
+       
 
4407
+       break;
 
4408
+    }
 
4409
+    default:
 
4410
+#if VERBOSE
 
4411
+       printf("WERT, can't evaluate if statement. %d is not a valid command",
 
4412
+              op);
 
4413
+#endif     
 
4414
+       return SIEVE_RUN_ERROR;
 
4415
+    }
 
4416
+    
 
4417
+  
 
4418
+ alldone:
 
4419
+    
 
4420
+    *ip=i;
 
4421
+    return res;
 
4422
+}
 
4423
+
 
4424
+/* The entrypoint for bytecode evaluation */
 
4425
+int sieve_eval_bc(sieve_interp_t *i, const void *bc_in, unsigned int bc_len,
 
4426
+                 void *m, sieve_imapflags_t * imapflags,
 
4427
+                 action_list_t *actions,
 
4428
+                 notify_list_t *notify_list,
 
4429
+                 const char **errmsg)
 
4430
+{
 
4431
+    const char *data;
 
4432
+    int ip = 0, ip_max = (bc_len/sizeof(bytecode_input_t));
 
4433
+    int res=0;
 
4434
+    int op;
 
4435
+    int version;
 
4436
+    
 
4437
+    bytecode_input_t *bc = (bytecode_input_t *)bc_in;
 
4438
+    
 
4439
+    /* Check that we
 
4440
+     * a) have bytecode
 
4441
+     * b) it is atleast long enough for the magic number, the version
 
4442
+     *    and one opcode */
 
4443
+    if(!bc) return SIEVE_FAIL;
 
4444
+    if(bc_len < (BYTECODE_MAGIC_LEN + 2*sizeof(bytecode_input_t)))
 
4445
+       return SIEVE_FAIL;
 
4446
+
 
4447
+    if(memcmp(bc, BYTECODE_MAGIC, BYTECODE_MAGIC_LEN)) {
 
4448
+       *errmsg = "Not a bytecode file";
 
4449
+       return SIEVE_FAIL;
 
4450
+    }
 
4451
+
 
4452
+    ip = BYTECODE_MAGIC_LEN / sizeof(bytecode_input_t);
 
4453
+
 
4454
+    version= ntohl(bc[ip].op);
 
4455
+
 
4456
+    /* this is because there was a time where integers were not network byte
 
4457
+       order.  all the scripts written then would have version 0x01 written
 
4458
+       in host byte order.*/
 
4459
+
 
4460
+     if(version == (int)ntohl(1)) {
 
4461
+       if(errmsg) {
 
4462
+           *errmsg =
 
4463
+               "Incorrect Bytecode Version, please recompile (use sievec)";
 
4464
+           
 
4465
+       }
 
4466
+       return SIEVE_FAIL;
 
4467
+    }
 
4468
+    
 
4469
+    if( version != BYTECODE_VERSION) {
 
4470
+       if(errmsg) {
 
4471
+           *errmsg =
 
4472
+               "Incorrect Bytecode Version, please recompile (use sievec)";
 
4473
+       }
 
4474
+       return SIEVE_FAIL;
 
4475
+    }
 
4476
+
 
4477
+#if VERBOSE
 
4478
+    printf("version number %d\n",version); 
 
4479
+#endif
 
4480
+
 
4481
+    for(ip++; ip<ip_max; ) { 
 
4482
+       op=ntohl(bc[ip].op);
 
4483
+       switch(op) {
 
4484
+       case B_STOP:/*0*/
 
4485
+           res=1;
 
4486
+           break;
 
4487
+
 
4488
+       case B_KEEP:/*1*/
 
4489
+           res = do_keep(actions, imapflags);
 
4490
+           if (res == SIEVE_RUN_ERROR)
 
4491
+               *errmsg = "Keep can not be used with Reject";
 
4492
+           ip++;
 
4493
+           break;
 
4494
+
 
4495
+       case B_DISCARD:/*2*/
 
4496
+           res=do_discard(actions);
 
4497
+           ip++;
 
4498
+           break;
 
4499
+
 
4500
+       case B_REJECT:/*3*/
 
4501
+           ip = unwrap_string(bc, ip+1, &data, NULL);
 
4502
+           
 
4503
+           res = do_reject(actions, data);
 
4504
+       
 
4505
+           if (res == SIEVE_RUN_ERROR)
 
4506
+               *errmsg = "Reject can not be used with any other action";  
 
4507
+
 
4508
+           break;
 
4509
+
 
4510
+       case B_FILEINTO:/*4*/
 
4511
+       {
 
4512
+           ip = unwrap_string(bc, ip+1, &data, NULL);
 
4513
+
 
4514
+           res = do_fileinto(actions, data, imapflags);
 
4515
+
 
4516
+           if (res == SIEVE_RUN_ERROR)
 
4517
+               *errmsg = "Fileinto can not be used with Reject";
 
4518
+
 
4519
+           break;
 
4520
+       }
 
4521
+
 
4522
+       case B_REDIRECT:/*5*/
 
4523
+       {
 
4524
+           ip = unwrap_string(bc, ip+1, &data, NULL);
 
4525
+
 
4526
+           res = do_redirect(actions, data);
 
4527
+
 
4528
+           if (res == SIEVE_RUN_ERROR)
 
4529
+               *errmsg = "Redirect can not be used with Reject";
 
4530
+
 
4531
+           break;
 
4532
+       }
 
4533
+
 
4534
+       case B_IF:/*6*/
 
4535
+       {
 
4536
+           int testend=ntohl(bc[ip+1].value);
 
4537
+           int result;
 
4538
+          
 
4539
+           ip+=2;
 
4540
+           result=eval_bc_test(i, m, bc, &ip);
 
4541
+           
 
4542
+           if (result<0) {
 
4543
+               *errmsg = "Invalid test";
 
4544
+               return SIEVE_FAIL;
 
4545
+           } else if (result) {
 
4546
+               /*skip over jump instruction*/
 
4547
+               testend+=2;
 
4548
+           }
 
4549
+           ip=testend;
 
4550
+           
 
4551
+           break;
 
4552
+       }
 
4553
+
 
4554
+       case B_MARK:/*8*/
 
4555
+           res = do_mark(actions);
 
4556
+           ip++;
 
4557
+           break;
 
4558
+
 
4559
+       case B_UNMARK:/*9*/
 
4560
+           res = do_unmark(actions);
 
4561
+           ip++;
 
4562
+           break;
 
4563
+
 
4564
+       case B_ADDFLAG:/*10*/ 
 
4565
+       {
 
4566
+           int x;
 
4567
+           int list_len=ntohl(bc[ip+1].len);
 
4568
+
 
4569
+           ip+=3; /* skip opcode, list_len, and list data len */
 
4570
+
 
4571
+           for (x=0; x<list_len; x++) {
 
4572
+               ip = unwrap_string(bc, ip, &data, NULL);
 
4573
+               
 
4574
+               res = do_addflag(actions, data);
 
4575
+
 
4576
+               if (res == SIEVE_RUN_ERROR)
 
4577
+                   *errmsg = "addflag can not be used with Reject";
 
4578
+           } 
 
4579
+           break;
 
4580
+       }
 
4581
+
 
4582
+       case B_SETFLAG:
 
4583
+       {
 
4584
+           int x;
 
4585
+           int list_len=ntohl(bc[ip+1].len);
 
4586
+
 
4587
+           ip+=3; /* skip opcode, list_len, and list data len */
 
4588
+
 
4589
+           ip = unwrap_string(bc, ip, &data, NULL);
 
4590
+
 
4591
+           res = do_setflag(actions, data);
 
4592
+
 
4593
+           if (res == SIEVE_RUN_ERROR) {
 
4594
+               *errmsg = "setflag can not be used with Reject";
 
4595
+           } else {
 
4596
+               for (x=1; x<list_len; x++) {
 
4597
+                   ip = unwrap_string(bc, ip, &data, NULL);
 
4598
+
 
4599
+                   res = do_addflag(actions, data);
 
4600
+
 
4601
+                   if (res == SIEVE_RUN_ERROR)
 
4602
+                       *errmsg = "setflag can not be used with Reject";
 
4603
+               } 
 
4604
+           }
 
4605
+           
 
4606
+           break;
 
4607
+       }
 
4608
+
 
4609
+       case B_REMOVEFLAG:
 
4610
+       {
 
4611
+           int x;
 
4612
+           int list_len=ntohl(bc[ip+1].len);
 
4613
+
 
4614
+           ip+=3; /* skip opcode, list_len, and list data len */
 
4615
+
 
4616
+           for (x=0; x<list_len; x++) {
 
4617
+               ip = unwrap_string(bc, ip, &data, NULL);
 
4618
+
 
4619
+               res = do_removeflag(actions, data);
 
4620
+
 
4621
+               if (res == SIEVE_RUN_ERROR)
 
4622
+                   *errmsg = "removeflag can not be used with Reject";
 
4623
+           } 
 
4624
+           break;
 
4625
+       }
 
4626
+
 
4627
+       case B_NOTIFY:
 
4628
+       {
 
4629
+           const char * id;
 
4630
+           const char * method;
 
4631
+           const char **options = NULL;
 
4632
+           const char *priority = NULL;
 
4633
+           const char * message;
 
4634
+           int pri;
 
4635
+           
 
4636
+           ip++;
 
4637
+
 
4638
+           /* method */
 
4639
+           ip = unwrap_string(bc, ip, &method, NULL);
 
4640
+
 
4641
+           /* id */
 
4642
+           ip = unwrap_string(bc, ip, &id, NULL);
 
4643
+
 
4644
+           /*options*/
 
4645
+           options=bc_makeArray(bc, &ip); 
 
4646
+
 
4647
+           /* priority */
 
4648
+           pri=ntohl(bc[ip].value);
 
4649
+           ip++;
 
4650
+           
 
4651
+           switch (pri)
 
4652
+           {
 
4653
+           case B_LOW:
 
4654
+               priority="low";
 
4655
+           case B_NORMAL:
 
4656
+               priority="normal";
 
4657
+               break;
 
4658
+           case B_HIGH: 
 
4659
+               priority="high";
 
4660
+               break; 
 
4661
+           case B_ANY:
 
4662
+               priority="any";
 
4663
+               break;
 
4664
+           default:
 
4665
+               res=SIEVE_RUN_ERROR;
 
4666
+           }
 
4667
+
 
4668
+           /* message */
 
4669
+           ip = unwrap_string(bc, ip, &message, NULL);
 
4670
+         
 
4671
+           res = do_notify(notify_list, id, method, options,
 
4672
+                           priority, message);
 
4673
+
 
4674
+           break;
 
4675
+       }
 
4676
+       case B_DENOTIFY:
 
4677
+       {
 
4678
+         /*
 
4679
+         * i really have no idea what the count matchtype should do here.
 
4680
+         * the sanest thing would be to use 1.
 
4681
+         * however that would require passing on the match type to do_notify.
 
4682
+         *  -jsmith2
 
4683
+         */
 
4684
+
 
4685
+           comparator_t *comp = NULL;
 
4686
+           
 
4687
+           const char *pattern;
 
4688
+           regex_t *reg;
 
4689
+           
 
4690
+           const char *priority = NULL;
 
4691
+           void *comprock = NULL;
 
4692
+           
 
4693
+           int comparator;
 
4694
+           int pri;
 
4695
+           
 
4696
+           ip++;
 
4697
+           pri=ntohl(bc[ip].value);
 
4698
+           ip++;
 
4699
+           
 
4700
+           switch (pri)
 
4701
+           {
 
4702
+           case B_LOW:
 
4703
+               priority="low";         
 
4704
+           case B_NORMAL:
 
4705
+               priority="normal";
 
4706
+               break;
 
4707
+           case B_HIGH: 
 
4708
+               priority="high";
 
4709
+               break; 
 
4710
+           case B_ANY:
 
4711
+               priority="any";
 
4712
+               break;
 
4713
+           default:
 
4714
+               res=SIEVE_RUN_ERROR;
 
4715
+           }
 
4716
+
 
4717
+           if(res == SIEVE_RUN_ERROR)
 
4718
+               break;
 
4719
+          
 
4720
+           comparator =ntohl( bc[ip].value);
 
4721
+           ip++;
 
4722
+           
 
4723
+           if (comparator == B_ANY)
 
4724
+           { 
 
4725
+               ip++;/* skip placeholder this has no comparator function */
 
4726
+               comp=NULL;
 
4727
+           } else {
 
4728
+               int x= ntohl(bc[ip].value);
 
4729
+               ip++;
 
4730
+               
 
4731
+               comp=lookup_comp(B_ASCIICASEMAP,comparator,
 
4732
+                                x, &comprock);
 
4733
+           }
 
4734
+           
 
4735
+           ip = unwrap_string(bc, ip, &pattern, NULL);
 
4736
+         
 
4737
+           if (comparator == B_REGEX)
 
4738
+           {   
 
4739
+               char errmsg[1024]; /* Basically unused */
 
4740
+               
 
4741
+               reg=bc_compile_regex(pattern,
 
4742
+                                    REG_EXTENDED | REG_NOSUB | REG_ICASE,
 
4743
+                                    errmsg, sizeof(errmsg));
 
4744
+               if (!reg) {
 
4745
+                   res = SIEVE_RUN_ERROR;
 
4746
+               } else {
 
4747
+                   res = do_denotify(notify_list, comp, reg,
 
4748
+                                     comprock, priority);
 
4749
+                   free(reg);
 
4750
+               }
 
4751
+           } else {
 
4752
+               res = do_denotify(notify_list, comp, pattern,
 
4753
+                                 comprock, priority);
 
4754
+           }
 
4755
+           
 
4756
+           break;
 
4757
+       }
 
4758
+       case B_VACATION:
 
4759
+       {
 
4760
+           int respond;
 
4761
+           char *fromaddr = NULL; /* relative to message we send */
 
4762
+           char *toaddr = NULL; /* relative to message we send */
 
4763
+           const char *message = NULL;
 
4764
+           char buf[128];
 
4765
+           char subject[1024];
 
4766
+           int x;
 
4767
+           
 
4768
+           ip++;
 
4769
+
 
4770
+           x=ntohl( bc[ip].len);
 
4771
+           
 
4772
+           respond=shouldRespond(m, i, x, bc, ip+2,
 
4773
+                                 &fromaddr, &toaddr);
 
4774
+           
 
4775
+           ip=(ntohl(bc[ip+1].value)/4);       
 
4776
+           if (respond==SIEVE_OK)
 
4777
+           {    
 
4778
+               ip = unwrap_string(bc, ip, &data, NULL);
 
4779
+               
 
4780
+               if (!data) 
 
4781
+               {
 
4782
+                   /* we have to generate a subject */
 
4783
+                   const char **s;         
 
4784
+                   strlcpy(buf, "subject", sizeof(buf));
 
4785
+                   if (i->getheader(m, buf, &s) != SIEVE_OK ||
 
4786
+                       s[0] == NULL) {
 
4787
+                       strlcpy(subject, "Automated reply", sizeof(subject));
 
4788
+                   } else {
 
4789
+                       /* s[0] contains the original subject */
 
4790
+                       const char *origsubj = s[0];
 
4791
+
 
4792
+                       while (!strncasecmp(origsubj, "Re: ", 4)) 
 
4793
+                           origsubj += 4;
 
4794
+
 
4795
+                       snprintf(subject, sizeof(subject), "Re: %s", origsubj);
 
4796
+                   }
 
4797
+               } else {
 
4798
+                   /* user specified subject */
 
4799
+                   strlcpy(subject, data, sizeof(subject));
 
4800
+               }
 
4801
+               
 
4802
+               ip = unwrap_string(bc, ip, &message, NULL);
 
4803
+
 
4804
+               res = do_vacation(actions, toaddr, fromaddr,
 
4805
+                                 xstrdup(subject), message,
 
4806
+                                 ntohl(bc[ip].value), ntohl(bc[ip+1].value));
 
4807
+
 
4808
+               ip+=2;          
 
4809
+
 
4810
+               if (res == SIEVE_RUN_ERROR)
 
4811
+                   *errmsg = "Vacation can not be used with Reject or Vacation";
 
4812
+           } else if (respond == SIEVE_DONE) {
 
4813
+                /* skip subject and message */
 
4814
+
 
4815
+               ip = unwrap_string(bc, ip, &data, NULL);
 
4816
+               ip = unwrap_string(bc, ip, &data, NULL);
 
4817
+
 
4818
+               ip+=2;/*skip days and mime flag*/
 
4819
+           } else {
 
4820
+               res = SIEVE_RUN_ERROR; /* something is bad */ 
 
4821
+           }
 
4822
+
 
4823
+           break;
 
4824
+       }
 
4825
+       case B_NULL:/*15*/
 
4826
+           ip++;
 
4827
+           break;
 
4828
+
 
4829
+       case B_JUMP:/*16*/
 
4830
+           ip= ntohl(bc[ip+1].jump);
 
4831
+           break;
 
4832
+           
 
4833
+       default:
 
4834
+           if(errmsg) *errmsg = "Invalid sieve bytecode";
 
4835
+           return SIEVE_FAIL;
 
4836
+       }
 
4837
+      
 
4838
+       if (res) /* we've either encountered an error or a stop */
 
4839
+           break;
 
4840
+    }
 
4841
+    return res;      
 
4842
+}
 
4843
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/bc_generate.c
 
4844
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
4845
+++ b/src/lib-sieve/cmu/libsieve/bc_generate.c  Sun May 04 16:00:59 2008 +0200
 
4846
@@ -0,0 +1,708 @@
 
4847
+/* bc_generate.c -- sieve bytecode- almost flattened bytecode
 
4848
+ * Rob Siemborski
 
4849
+ * $Id$
 
4850
+ */
 
4851
+/***********************************************************
 
4852
+        Copyright 2001 by Carnegie Mellon University
 
4853
+
 
4854
+                      All Rights Reserved
 
4855
+
 
4856
+Permission to use, copy, modify, and distribute this software and its
 
4857
+documentation for any purpose and without fee is hereby granted,
 
4858
+provided that the above copyright notice appear in all copies and that
 
4859
+both that copyright notice and this permission notice appear in
 
4860
+supporting documentation, and that the name of Carnegie Mellon
 
4861
+University not be used in advertising or publicity pertaining to
 
4862
+distribution of the software without specific, written prior
 
4863
+permission.
 
4864
+
 
4865
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
4866
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
4867
+FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
 
4868
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
4869
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
4870
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 
4871
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
4872
+******************************************************************/
 
4873
+
 
4874
+#ifdef HAVE_CONFIG_H
 
4875
+#include <config.h>
 
4876
+#endif
 
4877
+
 
4878
+#include "xmalloc.h"
 
4879
+#include "sieve_interface.h"
 
4880
+
 
4881
+#include "script.h"
 
4882
+#include "tree.h"
 
4883
+#include "sieve.h"
 
4884
+
 
4885
+#include "bytecode.h"
 
4886
+
 
4887
+#include <assert.h>
 
4888
+#include <string.h>
 
4889
+
 
4890
+
 
4891
+
 
4892
+struct bytecode_info 
 
4893
+{
 
4894
+    bytecode_t *data;/* pointer to almost-flat bytecode */
 
4895
+    size_t scriptend; /* used by emit code to know final length of bytecode */
 
4896
+    size_t reallen; /* allocated length of 'data' */
 
4897
+};
 
4898
+
 
4899
+static int bc_test_generate(int codep, bytecode_info_t *retval, test_t *t);
 
4900
+
 
4901
+/* returns false if the request can't be satisfied, true if it can. */
 
4902
+
 
4903
+static int atleast(bytecode_info_t *arr, size_t len) 
 
4904
+{
 
4905
+    if(arr->reallen < len) {
 
4906
+       /* too small; double if that's big enough, otherwise increase to the
 
4907
+          requested size. */
 
4908
+       arr->reallen = (len > arr->reallen * 2 ? len : arr->reallen * 2);
 
4909
+       arr->data = xrealloc(arr->data, arr->reallen*sizeof(bytecode_t));
 
4910
+       if(!arr->data) 
 
4911
+       { /* out of memory? */
 
4912
+           return 0;
 
4913
+       }
 
4914
+    }
 
4915
+    
 
4916
+    return 1;
 
4917
+}
 
4918
+
 
4919
+/*
 
4920
+ * functions of the form bc_XXX_generate have the following properties:
 
4921
+ * on success they return an int that corresponds to the next empty location
 
4922
+ * for code, and on failure they return -1.
 
4923
+ *
 
4924
+ *  they will take a  bytecode_info_t as a parameter and modify it by
 
4925
+ *  making it larger and adding more bytecommands in the pass 1 form
 
4926
+ */
 
4927
+
 
4928
+/* given a location and a string list, compile it into almost-flat form.
 
4929
+ * <list len> <string len><string ptr><string len><string ptr> etc... */
 
4930
+static int bc_stringlist_generate(int codep, bytecode_info_t *retval,
 
4931
+                                 stringlist_t *sl) 
 
4932
+{
 
4933
+    int len_codep = codep;
 
4934
+    int strcount = 0;
 
4935
+    stringlist_t *cur;
 
4936
+    
 
4937
+    codep++;
 
4938
+
 
4939
+    /* Bounds check the string list length */
 
4940
+    if(!atleast(retval,codep+1)) 
 
4941
+       return -1;
 
4942
+
 
4943
+    for(cur=sl; cur; cur=cur->next) 
 
4944
+    {
 
4945
+       strcount++;
 
4946
+       assert((cur->s)!=NULL);
 
4947
+       
 
4948
+       /* Bounds check for each string before we allocate it */
 
4949
+       if(!atleast(retval,codep+2)) 
 
4950
+           return -1;
 
4951
+
 
4952
+       retval->data[codep++].len = strlen(cur->s);
 
4953
+       retval->data[codep++].str = cur->s;
 
4954
+    }
 
4955
+    
 
4956
+    retval->data[len_codep].listlen = strcount;
 
4957
+    return codep;
 
4958
+}
 
4959
+
 
4960
+
 
4961
+/* write a list of tests into almost-flat form, starting at codep.
 
4962
+ * returns the next code location, -1 on error. */
 
4963
+
 
4964
+/* <list len> <next test ptr> <test ...> <next test ptr> <test ...> ... */
 
4965
+static int bc_testlist_generate(int codep, bytecode_info_t *retval, 
 
4966
+                               testlist_t *tl) 
 
4967
+{
 
4968
+    int len_codep = codep;
 
4969
+    int testcount = 0;
 
4970
+    testlist_t *cur;
 
4971
+    
 
4972
+    codep++;
 
4973
+
 
4974
+    /* Bounds check the test list length */
 
4975
+    if(!atleast(retval,codep+1)) 
 
4976
+       return -1;
 
4977
+       
 
4978
+    for(cur=tl; cur; cur=cur->next) {
 
4979
+       int oldcodep = codep;
 
4980
+
 
4981
+       /* Make room for tail marker */
 
4982
+       if(!atleast(retval,codep+1)) 
 
4983
+           return -1;
 
4984
+
 
4985
+       testcount++;
 
4986
+       codep = bc_test_generate(codep+1, retval, cur->t);
 
4987
+
 
4988
+       retval->data[oldcodep].jump = codep;
 
4989
+    }
 
4990
+
 
4991
+    retval->data[len_codep].listlen = testcount;
 
4992
+        
 
4993
+    return codep;
 
4994
+}
 
4995
+/* output a relation into almost-flat form at codep.
 
4996
+ * returns new codep on success, -1 on failure. */
 
4997
+static int bc_relation_generate(int codep, bytecode_info_t *retval, int relat)
 
4998
+{
 
4999
+    if (!atleast(retval, codep + 1)) return -1;
 
5000
+    switch (relat)
 
5001
+    {
 
5002
+    case GT:
 
5003
+       retval->data[codep++].value= B_GT;
 
5004
+       break;
 
5005
+    case GE:
 
5006
+       retval->data[codep++].value= B_GE;
 
5007
+       break; 
 
5008
+    case LT:
 
5009
+       retval->data[codep++].value= B_LT;
 
5010
+       break;
 
5011
+    case LE:
 
5012
+       retval->data[codep++].value= B_LE;
 
5013
+       break;
 
5014
+    case EQ:
 
5015
+       retval->data[codep++].value= B_EQ;
 
5016
+       break;
 
5017
+    case NE:
 
5018
+       retval->data[codep++].value= B_NE;
 
5019
+       break;
 
5020
+    default:
 
5021
+       /* comparator has no relational field */
 
5022
+       retval->data[codep++].value=  -1;
 
5023
+       break;
 
5024
+    }
 
5025
+    return codep;
 
5026
+}
 
5027
+/* writes a single comparator into almost-flat form starting at codep.
 
5028
+ * will always write out 3 words
 
5029
+ * returns the next code location or -1 on error. */
 
5030
+static int bc_comparator_generate(int codep, bytecode_info_t *retval,
 
5031
+                                  int comptag, int relat,
 
5032
+                                  const char *comparator)
 
5033
+{
 
5034
+    assert(retval != NULL);
 
5035
+
 
5036
+    /* comptag */
 
5037
+    if (!atleast(retval, codep + 1)) return -1;
 
5038
+
 
5039
+    switch (comptag) {
 
5040
+    case IS:
 
5041
+        retval->data[codep++].value = B_IS;
 
5042
+        break;
 
5043
+    case CONTAINS:
 
5044
+        retval->data[codep++].value = B_CONTAINS;
 
5045
+        break;
 
5046
+    case MATCHES:
 
5047
+        retval->data[codep++].value = B_MATCHES;
 
5048
+        break;
 
5049
+#ifdef ENABLE_REGEX
 
5050
+    case REGEX:
 
5051
+        retval->data[codep++].value = B_REGEX;
 
5052
+        break;
 
5053
+#endif
 
5054
+    case COUNT:
 
5055
+        retval->data[codep++].value = B_COUNT;
 
5056
+        break;
 
5057
+    case VALUE:
 
5058
+        retval->data[codep++].value = B_VALUE;
 
5059
+        break;
 
5060
+
 
5061
+    default:
 
5062
+        return -1;
 
5063
+    }
 
5064
+  
 
5065
+    /*relation*/
 
5066
+    codep = bc_relation_generate(codep, retval, relat);
 
5067
+  
 
5068
+    /* comparator (value specified with :comparator) */
 
5069
+    if (!atleast(retval, codep + 1)) return -1;
 
5070
+  
 
5071
+    /* xxx perhaps extend comparator.h to have
 
5072
+       lookup_comp return an index, and then
 
5073
+       lookup_by_index return the actual comparator?
 
5074
+       
 
5075
+       we can then eliminate the comptag above, too. */
 
5076
+    
 
5077
+    if (!strcmp (comparator, "i;octet"))
 
5078
+        retval->data[codep++].value = B_OCTET;
 
5079
+    else if (!strcmp (comparator, "i;ascii-casemap"))
 
5080
+        retval->data[codep++].value = B_ASCIICASEMAP;
 
5081
+    else if (!strcmp (comparator, "i;ascii-numeric"))
 
5082
+        retval->data[codep++].value = B_ASCIINUMERIC;
 
5083
+
 
5084
+    return codep;
 
5085
+}
 
5086
+
 
5087
+
 
5088
+
 
5089
+/* writes a single test into almost-flat form starting at codep.
 
5090
+ * returns the next code location or -1 on error. */
 
5091
+static int bc_test_generate(int codep, bytecode_info_t *retval, test_t *t)
 
5092
+{
 
5093
+    if(!retval) return -1;
 
5094
+    switch(t->type) {
 
5095
+    case STRUE: /* BC_TRUE */
 
5096
+       if(!atleast(retval,codep+1)) return -1;
 
5097
+       retval->data[codep++].op = BC_TRUE;
 
5098
+       break;
 
5099
+    case SFALSE:/* BC_FALSE */
 
5100
+       if(!atleast(retval,codep+1)) return -1;
 
5101
+       retval->data[codep++].op = BC_FALSE;
 
5102
+       break;
 
5103
+    case NOT: /* BC_NOT {subtest : test} */
 
5104
+       if(!atleast(retval,codep+1)) return -1;
 
5105
+       retval->data[codep++].op = BC_NOT;
 
5106
+       codep = bc_test_generate(codep, retval, t->u.t);
 
5107
+       if (codep == -1) return -1;
 
5108
+       break;
 
5109
+    case SIZE: /* BC_SIZE (B_OVER | B_UNDER) {size : int} */
 
5110
+       if(!atleast(retval,codep+3)) return -1;
 
5111
+       retval->data[codep++].op = BC_SIZE;
 
5112
+       retval->data[codep++].value = (t->u.sz.t == OVER
 
5113
+                                      ? B_OVER : B_UNDER);
 
5114
+       retval->data[codep++].value = t->u.sz.n;
 
5115
+       break;
 
5116
+    case EXISTS:/* BC_EXISTS { headers : string list } */
 
5117
+       if(!atleast(retval,codep+1)) return -1;
 
5118
+       retval->data[codep++].op = BC_EXISTS;
 
5119
+       codep= bc_stringlist_generate(codep, retval, t->u.sl);
 
5120
+       break;
 
5121
+    case ANYOF:/* BC_ANYOF { tests : test list } */
 
5122
+       if(!atleast(retval,codep+1)) return -1;
 
5123
+       retval->data[codep++].op = BC_ANYOF;
 
5124
+       codep=bc_testlist_generate(codep, retval, t->u.tl);
 
5125
+       if (codep == -1) return -1;
 
5126
+       break;
 
5127
+    case ALLOF: /* BC_ALLOF { tests : test list } */
 
5128
+       if(!atleast(retval,codep+1)) return -1;
 
5129
+       retval->data[codep++].op = BC_ALLOF;
 
5130
+       codep= bc_testlist_generate(codep, retval, t->u.tl);
 
5131
+       if (codep == -1) return -1;
 
5132
+       break;
 
5133
+    case HEADER:
 
5134
+       /* BC_HEADER { c: comparator } { headers : string list }
 
5135
+          { patterns : string list } 
 
5136
+       */
 
5137
+      
 
5138
+       if(!atleast(retval,codep + 1)) return -1;
 
5139
+       retval->data[codep++].op = BC_HEADER;
 
5140
+      
 
5141
+       /* comparator */
 
5142
+       codep = bc_comparator_generate(codep, retval,
 
5143
+                                      t->u.h.comptag,
 
5144
+                                      t->u.h.relation,
 
5145
+                                      t->u.h.comparator);
 
5146
+       if (codep == -1) return -1;
 
5147
+      
 
5148
+       /* headers */
 
5149
+       codep = bc_stringlist_generate(codep, retval, t->u.h.sl);
 
5150
+       if (codep == -1) return -1;
 
5151
+      
 
5152
+       /* pattern */
 
5153
+       codep = bc_stringlist_generate(codep, retval, t->u.h.pl);
 
5154
+       if (codep == -1) return -1;
 
5155
+       break;
 
5156
+    case ADDRESS:
 
5157
+    case ENVELOPE:
 
5158
+       /* (BC_ADDRESS | BC_ENVELOPE) {c : comparator} 
 
5159
+          (B_ALL | B_LOCALPART | ...) { header : string list }
 
5160
+          { pattern : string list } */
 
5161
+      
 
5162
+       if(!atleast(retval,codep+1)) return -1;
 
5163
+      
 
5164
+       retval->data[codep++].op = (t->type == ADDRESS)
 
5165
+           ? BC_ADDRESS : BC_ENVELOPE;
 
5166
+            
 
5167
+       codep = bc_comparator_generate(codep, retval,t->u.ae.comptag,
 
5168
+                                      t->u.ae.relation, 
 
5169
+                                      t->u.ae.comparator);
 
5170
+       if (codep == -1) return -1;
 
5171
+
 
5172
+       if(!atleast(retval,codep+1)) return -1;
 
5173
+
 
5174
+       /*address part*/
 
5175
+       switch(t->u.ae.addrpart) {
 
5176
+       case ALL:
 
5177
+           retval->data[codep++].value = B_ALL;
 
5178
+           break;
 
5179
+       case LOCALPART:
 
5180
+           retval->data[codep++].value = B_LOCALPART;
 
5181
+           break;
 
5182
+       case DOMAIN:
 
5183
+           retval->data[codep++].value = B_DOMAIN;
 
5184
+           break;
 
5185
+       case USER:
 
5186
+           retval->data[codep++].value = B_USER;
 
5187
+           break;
 
5188
+       case DETAIL:
 
5189
+           retval->data[codep++].value = B_DETAIL;
 
5190
+           break;
 
5191
+       default:
 
5192
+           return -1;
 
5193
+       }
 
5194
+
 
5195
+       /*headers*/
 
5196
+       codep = bc_stringlist_generate(codep, retval, t->u.ae.sl);
 
5197
+       if (codep == -1) return -1;
 
5198
+
 
5199
+       /*patterns*/
 
5200
+       codep = bc_stringlist_generate(codep, retval, t->u.ae.pl);
 
5201
+       if (codep == -1) return -1;
 
5202
+     
 
5203
+       break;
 
5204
+    default:
 
5205
+       return -1;
 
5206
+      
 
5207
+    }
 
5208
+    return codep;
 
5209
+}
 
5210
+
 
5211
+
 
5212
+/* generate a not-quite-flattened bytecode */
 
5213
+/* returns address of next instruction or -1 on error*/
 
5214
+/* needs current instruction, buffer for the code, and a current parse tree */
 
5215
+/* sieve is cool because everything is immediate! */
 
5216
+static int bc_action_generate(int codep, bytecode_info_t *retval,
 
5217
+                             commandlist_t *c) 
 
5218
+{
 
5219
+    int jumploc,baseloc;
 
5220
+
 
5221
+    if(!retval) return -1;
 
5222
+    if (c==NULL)
 
5223
+    {
 
5224
+       if(!atleast(retval,codep+1)) return -1;
 
5225
+       retval->data[codep++].op = B_NULL;
 
5226
+    }
 
5227
+    else
 
5228
+    {
 
5229
+       do {
 
5230
+           switch(c->type) {
 
5231
+           case STOP:
 
5232
+               /* STOP (no arguments) */
 
5233
+               if(!atleast(retval,codep+1)) return -1;
 
5234
+               retval->data[codep++].op = B_STOP;
 
5235
+               break;
 
5236
+           case DISCARD:
 
5237
+               /* DISCARD (no arguments) */
 
5238
+               if(!atleast(retval,codep+1)) return -1;
 
5239
+               retval->data[codep++].op = B_DISCARD;
 
5240
+               break;
 
5241
+           case KEEP:
 
5242
+               /* KEEP (no arguments) */
 
5243
+               if(!atleast(retval,codep+1)) return -1;
 
5244
+               retval->data[codep++].op = B_KEEP;
 
5245
+               break;
 
5246
+           case MARK:
 
5247
+               /* MARK (no arguments) */
 
5248
+               if(!atleast(retval,codep+1)) return -1;
 
5249
+               retval->data[codep++].op = B_MARK;
 
5250
+               break;
 
5251
+           case UNMARK:
 
5252
+               /* UNMARK (no arguments) */
 
5253
+               if(!atleast(retval,codep+1)) return -1;
 
5254
+               retval->data[codep++].op = B_UNMARK;
 
5255
+               break;
 
5256
+           case DENOTIFY:
 
5257
+               /* DENOTIFY  */
 
5258
+               if(!atleast(retval,codep+6)) return -1;
 
5259
+               retval->data[codep++].op = B_DENOTIFY;
 
5260
+               switch(c->u.d.priority) {
 
5261
+               case LOW:
 
5262
+                   retval->data[codep++].value = B_LOW;
 
5263
+                   break;
 
5264
+               case NORMAL:
 
5265
+                   retval->data[codep++].value = B_NORMAL;
 
5266
+                   break;
 
5267
+               case HIGH:
 
5268
+                   retval->data[codep++].value = B_HIGH;
 
5269
+                   break;
 
5270
+               case ANY:
 
5271
+                   retval->data[codep++].value = B_ANY;
 
5272
+                   break;
 
5273
+               default:
 
5274
+                   return -1;
 
5275
+               }
 
5276
+               switch(c->u.d.comptag) {
 
5277
+               case IS:
 
5278
+                   retval->data[codep++].value = B_IS;
 
5279
+                   break;
 
5280
+               case CONTAINS:
 
5281
+                   retval->data[codep++].value = B_CONTAINS;
 
5282
+                   break;
 
5283
+               case MATCHES:
 
5284
+                   retval->data[codep++].value = B_MATCHES;
 
5285
+                   break;
 
5286
+#ifdef ENABLE_REGEX
 
5287
+               case REGEX:
 
5288
+                   retval->data[codep++].value = B_REGEX;
 
5289
+                   break;
 
5290
+#endif
 
5291
+               case ANY:
 
5292
+                   retval->data[codep++].value = B_ANY;
 
5293
+                   break; 
 
5294
+               default:
 
5295
+                   return -1;
 
5296
+               }
 
5297
+               codep = bc_relation_generate(codep, retval, c->u.d.relation);
 
5298
+       
 
5299
+               if(c->u.d.pattern)
 
5300
+               {
 
5301
+                   retval->data[codep++].len = strlen(c->u.d.pattern);
 
5302
+                   retval->data[codep++].str = c->u.d.pattern;
 
5303
+               } else {
 
5304
+                   retval->data[codep++].len = -1;
 
5305
+                   retval->data[codep++].str = NULL;
 
5306
+               }
 
5307
+
 
5308
+               break;
 
5309
+           case REJCT:
 
5310
+               /* REJECT (STRING: len + dataptr) */
 
5311
+               if(!atleast(retval,codep+3)) return -1;
 
5312
+               retval->data[codep++].op = B_REJECT;
 
5313
+               retval->data[codep++].len = strlen(c->u.str);
 
5314
+               retval->data[codep++].str = c->u.str;
 
5315
+               break;
 
5316
+           case FILEINTO:
 
5317
+               /* FILEINTO (STRING: len + dataptr) */
 
5318
+               if(!atleast(retval,codep+3)) return -1;
 
5319
+               retval->data[codep++].op = B_FILEINTO;
 
5320
+               retval->data[codep++].len = strlen(c->u.str);
 
5321
+               retval->data[codep++].str = c->u.str;
 
5322
+               break;
 
5323
+           case REDIRECT:
 
5324
+               /* REDIRECT (STRING: len + dataptr) */
 
5325
+               if(!atleast(retval,codep+3)) return -1;
 
5326
+               retval->data[codep++].op = B_REDIRECT;
 
5327
+               retval->data[codep++].len = strlen(c->u.str);
 
5328
+               retval->data[codep++].str = c->u.str;
 
5329
+               break;
 
5330
+           case ADDFLAG:
 
5331
+               /* ADDFLAG stringlist */
 
5332
+               if(!atleast(retval,codep+1)) return -1;
 
5333
+               retval->data[codep++].op = B_ADDFLAG;
 
5334
+               codep = bc_stringlist_generate(codep,retval,c->u.sl);
 
5335
+
 
5336
+               if(codep == -1) return -1;
 
5337
+               break;
 
5338
+           case SETFLAG:
 
5339
+               /* SETFLAG stringlist */
 
5340
+               if(!atleast(retval,codep+1)) return -1;
 
5341
+               retval->data[codep++].op = B_SETFLAG;
 
5342
+               codep = bc_stringlist_generate(codep,retval,c->u.sl);
 
5343
+
 
5344
+               if(codep == -1) return -1;
 
5345
+               break;
 
5346
+           case REMOVEFLAG:
 
5347
+               /* REMOVEFLAG stringlist */
 
5348
+               if(!atleast(retval,codep+1)) return -1;
 
5349
+               retval->data[codep++].op = B_REMOVEFLAG;
 
5350
+               codep = bc_stringlist_generate(codep,retval,c->u.sl);
 
5351
+
 
5352
+               if(codep == -1) return -1;
 
5353
+               break;
 
5354
+           case NOTIFY:
 
5355
+               /* NOTIFY 
 
5356
+                  (STRING: len + dataptr)
 
5357
+                  (STRING: len + dataptr)
 
5358
+                  stringlist
 
5359
+                  (STRING: len + dataptr)
 
5360
+                  (STRING: len + dataptr)
 
5361
+                  method/id /options list/priority/message 
 
5362
+               */
 
5363
+                       
 
5364
+               if(!atleast(retval,codep+5)) return -1;
 
5365
+               retval->data[codep++].op = B_NOTIFY;
 
5366
+               
 
5367
+               retval->data[codep++].len = strlen(c->u.n.method);
 
5368
+               retval->data[codep++].str = c->u.n.method;
 
5369
+                               
 
5370
+               if (c->u.n.id)
 
5371
+               {
 
5372
+                   retval->data[codep++].len = strlen(c->u.n.id);
 
5373
+                   retval->data[codep++].str = c->u.n.id;
 
5374
+               }
 
5375
+               else
 
5376
+               {
 
5377
+                   retval->data[codep++].len = -1;
 
5378
+                   retval->data[codep++].str = NULL;
 
5379
+               }
 
5380
+               
 
5381
+               codep = bc_stringlist_generate(codep,retval,c->u.n.options);
 
5382
+               if(codep == -1) return -1;
 
5383
+
 
5384
+               if(!atleast(retval,codep+3)) return -1;
 
5385
+
 
5386
+               switch(c->u.n.priority) {
 
5387
+               case LOW:
 
5388
+                   retval->data[codep++].value = B_LOW;
 
5389
+                   break;
 
5390
+               case NORMAL:
 
5391
+                   retval->data[codep++].value = B_NORMAL;
 
5392
+                   break;
 
5393
+               case HIGH:
 
5394
+                   retval->data[codep++].value = B_HIGH;
 
5395
+                   break;
 
5396
+               case ANY:
 
5397
+                   retval->data[codep++].value = B_ANY;
 
5398
+                   break;
 
5399
+               default:
 
5400
+                   return -1;
 
5401
+               }
 
5402
+               
 
5403
+               retval->data[codep++].len = strlen(c->u.n.message);
 
5404
+               retval->data[codep++].str = c->u.n.message;
 
5405
+               break;
 
5406
+           case VACATION:
 
5407
+               /* VACATION
 
5408
+                  STRINGLIST addresses
 
5409
+                  STRING subject (if len is -1, then subject was NULL)
 
5410
+                  STRING message (again, len == -1 means subject was NULL)
 
5411
+                  VALUE days
 
5412
+                  VALUE mime
 
5413
+               */
 
5414
+
 
5415
+               if(!atleast(retval,codep+1)) return -1;
 
5416
+               retval->data[codep++].op = B_VACATION;
 
5417
+           
 
5418
+               codep = bc_stringlist_generate(codep,retval,c->u.v.addresses);
 
5419
+               if (codep == -1) return -1;
 
5420
+
 
5421
+               if (!atleast(retval,codep+2)) return -1;
 
5422
+               if(c->u.v.subject) {
 
5423
+                   retval->data[codep++].len = strlen(c->u.v.subject);
 
5424
+                   retval->data[codep++].str = c->u.v.subject;
 
5425
+               } else {
 
5426
+                   retval->data[codep++].len = -1;
 
5427
+                   retval->data[codep++].str = NULL;
 
5428
+               }
 
5429
+
 
5430
+               if (!atleast(retval,codep+2)) return -1;
 
5431
+               if(c->u.v.message) {
 
5432
+                   retval->data[codep++].len = strlen(c->u.v.message);
 
5433
+                   retval->data[codep++].str = c->u.v.message;
 
5434
+               } else {
 
5435
+                   retval->data[codep++].len = -1;
 
5436
+                   retval->data[codep++].str = NULL;
 
5437
+               }
 
5438
+
 
5439
+               if (!atleast(retval,codep+2)) return -1;
 
5440
+               retval->data[codep++].value = c->u.v.days;
 
5441
+               retval->data[codep++].value = c->u.v.mime;
 
5442
+           
 
5443
+
 
5444
+               if(codep == -1) return -1;
 
5445
+               break;
 
5446
+           case IF:
 
5447
+           {
 
5448
+               int jumpVal;        
 
5449
+               /* IF
 
5450
+                  (int: begin then block)
 
5451
+                  (int: end then block/begin else block)
 
5452
+                  (int:end else block) (-1 if no else block)
 
5453
+                  (test)
 
5454
+                  (then block)
 
5455
+                  (else block)(optional)
 
5456
+               */
 
5457
+               baseloc = codep;
 
5458
+           
 
5459
+               /* Allocate operator + jump table offsets */
 
5460
+               if(!atleast(retval,codep+4)) return -1;
 
5461
+               
 
5462
+               jumploc = codep+4;
 
5463
+               retval->data[codep++].op = B_IF;
 
5464
+                   
 
5465
+               /* begining of then  code */
 
5466
+               jumpVal= bc_test_generate(jumploc,retval,c->u.i.t);
 
5467
+               if(jumpVal == -1) 
 
5468
+                   return -1;
 
5469
+               else {
 
5470
+                   retval->data[codep].jump = jumpVal;
 
5471
+                   codep++;
 
5472
+               }
 
5473
+           
 
5474
+               /* find then code and offset to else code,
 
5475
+                * we want to write this code starting at the offset we
 
5476
+                * just found */
 
5477
+       
 
5478
+               jumpVal= bc_action_generate(jumpVal,retval, c->u.i.do_then);
 
5479
+               if(jumpVal == -1) 
 
5480
+                   return -1;
 
5481
+               else 
 
5482
+                   retval->data[codep].jump = jumpVal;
 
5483
+               
 
5484
+               codep++;
 
5485
+               /* write else code if its there*/
 
5486
+               if(c->u.i.do_else) {
 
5487
+       
 
5488
+                   jumpVal= bc_action_generate(jumpVal,retval, c->u.i.do_else);
 
5489
+                   if(jumpVal == -1) 
 
5490
+                   {
 
5491
+                       return -1;
 
5492
+                   } else 
 
5493
+                   {
 
5494
+                       retval->data[codep].jump = jumpVal;
 
5495
+                   }
 
5496
+                   
 
5497
+                   /* Update code pointer to end of else code */
 
5498
+                   codep = retval->data[codep].jump;
 
5499
+               } else {
 
5500
+                   /*there is no else block, so its -1*/
 
5501
+                   retval->data[codep].jump = -1;
 
5502
+                   /* Update code pointer to end of then code */
 
5503
+                   codep = retval->data[codep-1].jump;
 
5504
+               }
 
5505
+           
 
5506
+               break;
 
5507
+           }
 
5508
+           default:
 
5509
+               /* no such action known */
 
5510
+               return -1;
 
5511
+           }
 
5512
+         
 
5513
+           /* generate from next command */
 
5514
+           c = c->next;
 
5515
+       } while(c);
 
5516
+    }
 
5517
+    /*scriptend may be updated before the end, but it will be updated at the end, which is what matters.*/
 
5518
+    retval->scriptend=codep;
 
5519
+    return codep;
 
5520
+   
 
5521
+}
 
5522
+
 
5523
+
 
5524
+
 
5525
+/* Entry point to the bytecode emitter module */       
 
5526
+int sieve_generate_bytecode(bytecode_info_t **retval, sieve_script_t *s) 
 
5527
+{
 
5528
+    commandlist_t *c;
 
5529
+
 
5530
+    if(!retval) return -1;
 
5531
+    if(!s) return -1;
 
5532
+    c = s->cmds;
 
5533
+    /* if c is NULL, it is handled in bc_action_generate and a script
 
5534
+       with only BC_NULL is returned
 
5535
+    */
 
5536
+
 
5537
+    
 
5538
+    *retval = xmalloc(sizeof(bytecode_info_t));
 
5539
+    if(!(*retval)) return -1;
 
5540
+
 
5541
+    memset(*retval, 0, sizeof(bytecode_info_t));
 
5542
+
 
5543
+    return bc_action_generate(0, *retval, c);
 
5544
+}
 
5545
+
 
5546
+
 
5547
+void sieve_free_bytecode(bytecode_info_t **p) 
 
5548
+{
 
5549
+    if(!p || !*p) return;
 
5550
+    if((*p)->data) free((*p)->data);
 
5551
+    free(*p);
 
5552
+    *p = NULL;
 
5553
+}
 
5554
 
5555
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/bytecode.h
 
5556
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
5557
+++ b/src/lib-sieve/cmu/libsieve/bytecode.h     Sun May 04 16:00:59 2008 +0200
 
5558
@@ -0,0 +1,193 @@
 
5559
+/* bytecode.h -- bytecode definition
 
5560
+ */
 
5561
+/***********************************************************
 
5562
+        Copyright 1999 by Carnegie Mellon University
 
5563
+
 
5564
+                      All Rights Reserved
 
5565
+
 
5566
+Permission to use, copy, modify, and distribute this software and its
 
5567
+documentation for any purpose and without fee is hereby granted,
 
5568
+provided that the above copyright notice appear in all copies and that
 
5569
+both that copyright notice and this permission notice appear in
 
5570
+supporting documentation, and that the name of Carnegie Mellon
 
5571
+University not be used in advertising or publicity pertaining to
 
5572
+distribution of the software without specific, written prior
 
5573
+permission.
 
5574
+
 
5575
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
5576
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
5577
+FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
 
5578
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
5579
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
5580
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 
5581
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
5582
+*****************************************************************/
 
5583
+
 
5584
+#ifndef SIEVE_BYTECODE_H
 
5585
+#define SIEVE_BYTECODE_H
 
5586
+
 
5587
+
 
5588
+/* for debugging*/
 
5589
+#define DUMPCODE 0
 
5590
+#define VERBOSE 0
 
5591
+
 
5592
+/*for finding correctly aligned bytes on strings*/
 
5593
+/* bump to the next multiple of 4 bytes */
 
5594
+#define ROUNDUP(num) (((num) + 3) & 0xFFFFFFFC)
 
5595
+
 
5596
+
 
5597
+/* yes, lots of these are superfluous, it's for clarity */
 
5598
+typedef union 
 
5599
+{
 
5600
+    int op; /* OPTYPE */
 
5601
+    int value;
 
5602
+
 
5603
+    int jump;
 
5604
+
 
5605
+    int listlen;
 
5606
+
 
5607
+    /* store strings (need 2 consecutive bytecodes) */
 
5608
+    int len;
 
5609
+    char *str;
 
5610
+} bytecode_t;
 
5611
+
 
5612
+/* For sanity during input on 64-bit platforms.
 
5613
+ * str should only be accessed as (char *)&str, but given the use of
 
5614
+ * unwrap_string, this should be OK */
 
5615
+typedef union 
 
5616
+{
 
5617
+    int op; /* OPTYPE */
 
5618
+    int value;
 
5619
+
 
5620
+    int jump;
 
5621
+
 
5622
+    int listlen;
 
5623
+
 
5624
+    /* store strings (need 2 consecutive bytecodes) */
 
5625
+    int len;
 
5626
+    int str;
 
5627
+} bytecode_input_t;
 
5628
+
 
5629
+
 
5630
+   /*version 0x01 scripts were written in host byte order.
 
5631
+   we don't want to use this version number again and cause a mess
 
5632
+   this isn't a huge concern, since this is version ntohl(1), or 16777216*/
 
5633
+#define BYTECODE_VERSION 0x03
 
5634
+#define BYTECODE_MAGIC "CyrSBytecode"
 
5635
+#define BYTECODE_MAGIC_LEN 12 /* Should be multiple of 4 */
 
5636
+
 
5637
+/* IMPORTANT: To maintain forward compatibility of bytecode, please only add
 
5638
+ * new instructions to the end of these enums.  (The reason these values
 
5639
+ * are all duplicated here is to avoid silliness if this caveat is forgotten
 
5640
+ * about in the other tables.) */
 
5641
+enum bytecode {
 
5642
+    B_STOP,
 
5643
+
 
5644
+    B_KEEP,
 
5645
+    B_DISCARD,
 
5646
+    B_REJECT,/* require reject*/
 
5647
+    B_FILEINTO,/*require fileinto*/
 
5648
+    B_REDIRECT,
 
5649
+
 
5650
+    B_IF,
 
5651
+  
 
5652
+    B_MARK,/* require imapflags */
 
5653
+    B_UNMARK,/* require imapflags */
 
5654
+
 
5655
+    B_ADDFLAG,/* require imapflags */
 
5656
+    B_SETFLAG,/* require imapflags */
 
5657
+    B_REMOVEFLAG,/* require imapflags */
 
5658
+
 
5659
+    B_NOTIFY,/* require notify */
 
5660
+    B_DENOTIFY,/* require notify */
 
5661
+
 
5662
+    B_VACATION,/* require vacation*/
 
5663
+    B_NULL,
 
5664
+    B_JUMP
 
5665
+};
 
5666
+
 
5667
+enum bytecode_comps {
 
5668
+    BC_FALSE,
 
5669
+    BC_TRUE,
 
5670
+    BC_NOT,
 
5671
+    BC_EXISTS,
 
5672
+    BC_SIZE,
 
5673
+    BC_ANYOF,
 
5674
+    BC_ALLOF,
 
5675
+    BC_ADDRESS,
 
5676
+    BC_ENVELOPE,  /* require envelope*/
 
5677
+    BC_HEADER    
 
5678
+};
 
5679
+
 
5680
+/* currently one enum so as to help determine where values are being misused.
 
5681
+ * we have left placeholders incase we need to add more later to the middle */
 
5682
+enum bytecode_tags {
 
5683
+    /* Sizes */
 
5684
+    B_OVER,
 
5685
+    B_UNDER,
 
5686
+
 
5687
+    B_SIZE_PLACEHOLDER_1,
 
5688
+    B_SIZE_PLACEHOLDER_2,
 
5689
+     
 
5690
+    /* sizes, pt 2 */
 
5691
+    B_GT, /* require relational*/
 
5692
+    B_GE,  /* require relational*/
 
5693
+    B_LT,  /* require relational*/
 
5694
+    B_LE,  /* require relational*/
 
5695
+    B_EQ,  /* require relational*/
 
5696
+    B_NE,  /* require relational*/
 
5697
 
5698
+    B_RELATIONAL_PLACEHOLDER_1,
 
5699
+    B_RELATIONAL_PLACEHOLDER_2,
 
5700
+   
 
5701
+    /* priorities */
 
5702
+    B_LOW,
 
5703
+    B_NORMAL,
 
5704
+    B_HIGH,
 
5705
+    B_ANY,
 
5706
+
 
5707
+    B_PRIORITY_PLACEHOLDER_1,
 
5708
+    B_PRIORITY_PLACEHOLDER_2,
 
5709
+    B_PRIORITY_PLACEHOLDER_3,
 
5710
+    B_PRIORITY_PLACEHOLDER_4,
 
5711
+    
 
5712
+    /* Address Part Tags */
 
5713
+    B_ALL,
 
5714
+    B_LOCALPART,
 
5715
+    B_DOMAIN,
 
5716
+    B_USER,  /* require subaddress */
 
5717
+    B_DETAIL, /* require subaddress */
 
5718
+    
 
5719
+    B_ADDRESS_PLACEHOLDER_1,
 
5720
+    B_ADDRESS_PLACEHOLDER_2,
 
5721
+    B_ADDRESS_PLACEHOLDER_3,
 
5722
+    B_ADDRESS_PLACEHOLDER_4,
 
5723
+
 
5724
+    /* Comparators */
 
5725
+    B_ASCIICASEMAP,
 
5726
+    B_OCTET,
 
5727
+    B_ASCIINUMERIC, /* require comparator-i;ascii-numeric */
 
5728
+    
 
5729
+    B_COMPARATOR_PLACEHOLDER_1,
 
5730
+    B_COMPARATOR_PLACEHOLDER_2,
 
5731
+    B_COMPARATOR_PLACEHOLDER_3,
 
5732
+    B_COMPARATOR_PLACEHOLDER_4,
 
5733
 
5734
+    /* match types */
 
5735
+    B_IS,
 
5736
+    B_CONTAINS,
 
5737
+    B_MATCHES,
 
5738
+    B_REGEX,/* require regex*/
 
5739
+    B_COUNT,/* require relational*/
 
5740
+    B_VALUE,/* require relational*/
 
5741
+
 
5742
+    B_MATCH_PLACEHOLDER_1,
 
5743
+    B_MATCH_PLACEHOLDER_2,
 
5744
+    B_MATCH_PLACEHOLDER_3,
 
5745
+    B_MATCH_PLACEHOLDER_4
 
5746
+  
 
5747
+};
 
5748
+
 
5749
+int unwrap_string(bytecode_input_t *bc, int pos, const char **str, int *len);
 
5750
+
 
5751
+#endif
 
5752
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/comparator.c
 
5753
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
5754
+++ b/src/lib-sieve/cmu/libsieve/comparator.c   Sun May 04 16:00:59 2008 +0200
 
5755
@@ -0,0 +1,448 @@
 
5756
+/* comparator.c -- comparator functions
 
5757
+ * Larry Greenfield
 
5758
+ * $Id$
 
5759
+ */
 
5760
+/***********************************************************
 
5761
+        Copyright 1999 by Carnegie Mellon University
 
5762
+
 
5763
+                      All Rights Reserved
 
5764
+
 
5765
+Permission to use, copy, modify, and distribute this software and its
 
5766
+documentation for any purpose and without fee is hereby granted,
 
5767
+provided that the above copyright notice appear in all copies and that
 
5768
+both that copyright notice and this permission notice appear in
 
5769
+supporting documentation, and that the name of Carnegie Mellon
 
5770
+University not be used in advertising or publicity pertaining to
 
5771
+distribution of the software without specific, written prior
 
5772
+permission.
 
5773
+
 
5774
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
5775
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
5776
+FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
 
5777
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
5778
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
5779
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 
5780
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
5781
+******************************************************************/
 
5782
+
 
5783
+#ifdef HAVE_CONFIG_H
 
5784
+#include <config.h>
 
5785
+#endif
 
5786
+
 
5787
+#include <stdlib.h>
 
5788
+#include <ctype.h>
 
5789
+#include <string.h>
 
5790
+
 
5791
+#include "xmalloc.h"
 
5792
+#include "comparator.h"
 
5793
+#include "tree.h"
 
5794
+#include "sieve.h"
 
5795
+#include "bytecode.h"
 
5796
+
 
5797
+/*!!! uses B_CONTAINS not CONTAINS, etc, only works with bytecode*/
 
5798
+
 
5799
+extern int strcasecmp(const char *, const char *);
 
5800
+
 
5801
+typedef int (*compare_t)(const void *, const void *);
 
5802
+
 
5803
+/* --- relational comparators --- */
 
5804
+
 
5805
+/* these are generic wrappers in which 'rock' is the compare function */
 
5806
+
 
5807
+static int rel_eq(const char *text, const char *pat, void *rock)
 
5808
+{
 
5809
+    compare_t compar = (compare_t) rock;
 
5810
+
 
5811
+    return (compar(text, pat) == 0);
 
5812
+}
 
5813
+
 
5814
+static int rel_ne(const char *text, const char *pat, void *rock)
 
5815
+{
 
5816
+    compare_t compar = (compare_t) rock;
 
5817
+
 
5818
+    return (compar(text, pat) != 0);
 
5819
+}
 
5820
+
 
5821
+static int rel_gt(const char *text, const char *pat, void *rock)
 
5822
+{
 
5823
+    compare_t compar = (compare_t) rock;
 
5824
+
 
5825
+    return (compar(text, pat) > 0);
 
5826
+}
 
5827
+
 
5828
+static int rel_ge(const char *text, const char *pat, void *rock)
 
5829
+{
 
5830
+    compare_t compar = (compare_t) rock;
 
5831
+
 
5832
+    return (compar(text, pat) >= 0);
 
5833
+}
 
5834
+
 
5835
+static int rel_lt(const char *text, const char *pat, void *rock)
 
5836
+{
 
5837
+    compare_t compar = (compare_t) rock;
 
5838
+
 
5839
+    return (compar(text, pat) < 0);
 
5840
+}
 
5841
+
 
5842
+static int rel_le(const char *text, const char *pat, void *rock)
 
5843
+{
 
5844
+    compare_t compar = (compare_t) rock;
 
5845
+
 
5846
+    return (compar(text, pat) <= 0);
 
5847
+}
 
5848
+
 
5849
+/* --- i;octet comparators --- */
 
5850
+
 
5851
+/* just compare the two; these should be NULL terminated */
 
5852
+static int octet_cmp(const char *text, const char *pat)
 
5853
+{
 
5854
+    size_t sl;
 
5855
+    int r;
 
5856
+
 
5857
+    sl = strlen(text) < strlen(pat) ? strlen(text) : strlen(pat);
 
5858
+
 
5859
+    r = memcmp(text, pat, sl);
 
5860
+
 
5861
+    if (r == 0)
 
5862
+       return (strlen(text) - strlen(pat));
 
5863
+    else 
 
5864
+       return r;
 
5865
+}
 
5866
+
 
5867
+/* we implement boyer-moore for hell of it, since this is probably
 
5868
+ not very useful for sieve */
 
5869
+#if 0
 
5870
+int boyer_moore(char *text, char *pat)
 
5871
+{
 
5872
+    int i, j; /* indexes */
 
5873
+    int M = strlen(pat); /* length of pattern */
 
5874
+    int N = strlen(text); /* length of text */
 
5875
+    int skip[256]; /* table of how much to skip, based on each character */
 
5876
+
 
5877
+    /* initialize skip table */
 
5878
+    for (i = 0; i < 256; i++)
 
5879
+       skip[i] = M;
 
5880
+    for (i = 0; i < M; i++)
 
5881
+       skip[(int) pat[i]] = M-i-1;
 
5882
+    
 
5883
+    /* look for pat in text */
 
5884
+    i = j = M-1;
 
5885
+    do {
 
5886
+       if (pat[j] == text[i]) {
 
5887
+           i--;
 
5888
+           j--;
 
5889
+       } else {
 
5890
+           if (M-j > skip[(int) text[i]]) {
 
5891
+               i = i + M - j;
 
5892
+           } else {
 
5893
+               i = i + skip[(int) text[i]];
 
5894
+           }
 
5895
+           j = M-1;
 
5896
+       }
 
5897
+    } while (!((j < 0) || (i >= N)));
 
5898
+    /* i+1 is the position of the match if i < N */
 
5899
+    return (i < N) ? 1 : 0;
 
5900
+}
 
5901
+#endif
 
5902
+
 
5903
+/* we do a brute force attack */
 
5904
+static int octet_contains(const char *text, const char *pat, 
 
5905
+                          void *rock __attr_unused__)
 
5906
+{
 
5907
+    return (strstr(text, pat) != NULL);
 
5908
+}
 
5909
+
 
5910
+static int octet_matches_(const char *text, const char *pat, int casemap)
 
5911
+{
 
5912
+    const char *p;
 
5913
+    const char *t;
 
5914
+    char c;
 
5915
+
 
5916
+    t = text;
 
5917
+    p = pat;
 
5918
+    for (;;) {
 
5919
+       if (*p == '\0') {
 
5920
+           /* ran out of pattern */
 
5921
+           return (*t == '\0');
 
5922
+       }
 
5923
+       c = *p++;
 
5924
+       switch (c) {
 
5925
+       case '?':
 
5926
+           if (*t == '\0') {
 
5927
+               return 0;
 
5928
+           }
 
5929
+           t++;
 
5930
+           break;
 
5931
+       case '*':
 
5932
+           while (*p == '*' || *p == '?') {
 
5933
+               if (*p == '?') {
 
5934
+                   /* eat the character now */
 
5935
+                   if (*t == '\0') {
 
5936
+                       return 0;
 
5937
+                   }
 
5938
+                   t++;
 
5939
+               }
 
5940
+               /* coalesce into a single wildcard */
 
5941
+               p++;
 
5942
+           }
 
5943
+           if (*p == '\0') {
 
5944
+               /* wildcard at end of string, any remaining text is ok */
 
5945
+               return 1;
 
5946
+           }
 
5947
+
 
5948
+           while (*t != '\0') {
 
5949
+               /* recurse */
 
5950
+               if (octet_matches_(t, p, casemap)) return 1;
 
5951
+               t++;
 
5952
+           }
 
5953
+       case '\\':
 
5954
+           p++;
 
5955
+           /* falls through */
 
5956
+       default:
 
5957
+           if (casemap && (toupper(c) == toupper(*t))) {
 
5958
+               t++;
 
5959
+           } else if (!casemap && (c == *t)) {
 
5960
+               t++;
 
5961
+           } else {
 
5962
+               /* literal char doesn't match */
 
5963
+               return 0;
 
5964
+           }
 
5965
+       }
 
5966
+    }
 
5967
+    /* never reaches */
 
5968
+    abort();
 
5969
+}
 
5970
+
 
5971
+static int octet_matches(const char *text, const char *pat, 
 
5972
+                         void *rock __attr_unused__)
 
5973
+{
 
5974
+    return octet_matches_(text, pat, 0);
 
5975
+}
 
5976
+
 
5977
+
 
5978
+#ifdef ENABLE_REGEX
 
5979
+static int octet_regex(const char *text, const char *pat, 
 
5980
+                       void *rock __attr_unused__)
 
5981
+{
 
5982
+    return (!regexec((regex_t *) pat, text, 0, NULL, 0));
 
5983
+}
 
5984
+#endif
 
5985
+
 
5986
+
 
5987
+/* --- i;ascii-casemap comparators --- */
 
5988
+
 
5989
+
 
5990
+/* use strcasecmp() as the compare function */
 
5991
+
 
5992
+/* sheer brute force */
 
5993
+static int ascii_casemap_contains(const char *text, const char *pat,
 
5994
+                                 void *rock __attr_unused__)
 
5995
+{
 
5996
+    int N = strlen(text);
 
5997
+    int M = strlen(pat);
 
5998
+    int i, j;
 
5999
+
 
6000
+    i = 0, j = 0;
 
6001
+    while ((j < M) && (i < N)) {
 
6002
+              if (toupper(text[i]) == toupper(pat[j])) {
 
6003
+                 i++; j++;
 
6004
+       } else {
 
6005
+           i = i - j + 1;
 
6006
+           j = 0;
 
6007
+       }
 
6008
+    }    
 
6009
+
 
6010
+    return (j == M); /* we found a match! */
 
6011
+}
 
6012
+
 
6013
+static int ascii_casemap_matches(const char *text, const char *pat, 
 
6014
+                                 void *rock __attr_unused__)
 
6015
+{
 
6016
+    return octet_matches_(text, pat, 1);
 
6017
+}
 
6018
+
 
6019
+/* i;ascii-numeric; only supports relational tests
 
6020
+ *
 
6021
+ *  A \ B    number   not-num 
 
6022
+ *  number   A ? B    B > A 
 
6023
+ *  not-num  A > B    A == B
 
6024
+ */
 
6025
+
 
6026
+ /* From RFC 2244:
 
6027
+  *
 
6028
+  * The i;ascii-numeric comparator interprets strings as decimal
 
6029
+  * positive integers represented as US-ASCII digits.  All values
 
6030
+  * which do not begin with a US-ASCII digit are considered equal
 
6031
+  * with an ordinal value higher than all non-NIL single-valued
 
6032
+  * attributes.  Otherwise, all US-ASCII digits (octet values
 
6033
+  * 0x30 to 0x39) are interpreted starting from the beginning of
 
6034
+  * the string to the first non-digit or the end of the string.
 
6035
+  */
 
6036
+
 
6037
+static int ascii_numeric_cmp(const char *text, const char *pat)
 
6038
+{
 
6039
+    unsigned text_digit_len;
 
6040
+    unsigned pat_digit_len;
 
6041
+
 
6042
+    if (isdigit((int) *pat)) {
 
6043
+       if (isdigit((int) *text)) {
 
6044
+           /* Count how many digits each string has */
 
6045
+           for (text_digit_len = 0;
 
6046
+                isdigit((int) text[text_digit_len]);
 
6047
+                text_digit_len++);
 
6048
+           for (pat_digit_len = 0;
 
6049
+                isdigit((int) pat[pat_digit_len]);
 
6050
+                pat_digit_len++);
 
6051
+
 
6052
+           if (text_digit_len < pat_digit_len) {
 
6053
+               /* Pad "text" with leading 0s */
 
6054
+               while (pat_digit_len > text_digit_len) {
 
6055
+                   /* "text" can only be less or equal to "pat" */
 
6056
+                   if ('0' < *pat) {
 
6057
+                       return (-1); 
 
6058
+                   }
 
6059
+                   pat++;
 
6060
+                   pat_digit_len--;
 
6061
+               }
 
6062
+           } else if (text_digit_len > pat_digit_len) {
 
6063
+               /* Pad "pad" with leading 0s */
 
6064
+               while (text_digit_len > pat_digit_len) {
 
6065
+                   /* "pad" can only be greater or equal to "text" */
 
6066
+                   if (*text > '0') {
 
6067
+                       return 1;
 
6068
+                   }
 
6069
+                   text++;
 
6070
+                   text_digit_len--;
 
6071
+               }
 
6072
+           }
 
6073
+
 
6074
+           /* CLAIM: If we here, we have two non-empty digital suffixes
 
6075
+              of equal length */
 
6076
+           while (text_digit_len > 0) {
 
6077
+               if (*text < *pat) {
 
6078
+                       return -1;
 
6079
+               } else if (*text > *pat) {
 
6080
+                       return 1;
 
6081
+               }
 
6082
+               /* Characters are equal, carry on */
 
6083
+               text++;
 
6084
+               pat++;
 
6085
+               text_digit_len--;
 
6086
+           }
 
6087
+
 
6088
+           return (0);
 
6089
+       } else {
 
6090
+           return 1;
 
6091
+       }
 
6092
+    } else if (isdigit((int) *text)) {
 
6093
+       return -1;
 
6094
+    } else {
 
6095
+       return 0; /* both not digits */
 
6096
+    }
 
6097
+}
 
6098
+
 
6099
+static comparator_t *lookup_rel(int relation)
 
6100
+{
 
6101
+    comparator_t *ret;
 
6102
+
 
6103
+    ret = NULL;
 
6104
+    switch (relation)
 
6105
+      {
 
6106
+      case B_EQ:
 
6107
+       ret = &rel_eq;
 
6108
+       break;
 
6109
+      case B_NE:
 
6110
+       ret = &rel_ne; 
 
6111
+       break;
 
6112
+      case B_GT: 
 
6113
+       ret = &rel_gt; 
 
6114
+       break;
 
6115
+      case B_GE:
 
6116
+         ret = &rel_ge; 
 
6117
+        break;
 
6118
+      case B_LT:
 
6119
+       ret = &rel_lt; 
 
6120
+       break;
 
6121
+      case B_LE:
 
6122
+       ret = &rel_le; 
 
6123
+      }
 
6124
+
 
6125
+    return ret;
 
6126
+}
 
6127
+
 
6128
+comparator_t *lookup_comp(int comp, int mode, int relation,
 
6129
+                         void **comprock)
 
6130
+{
 
6131
+    comparator_t *ret;
 
6132
+
 
6133
+    ret = NULL;
 
6134
+    *comprock = NULL;
 
6135
+#if VERBOSE
 
6136
+    printf("comp%d mode%d relat%d     \n", comp, mode, relation); 
 
6137
+#endif
 
6138
+    switch (comp)
 
6139
+      {
 
6140
+      case B_OCTET:    
 
6141
+       switch (mode) {
 
6142
+         case B_IS:
 
6143
+           ret = &rel_eq;
 
6144
+           *comprock = (void **) &octet_cmp;
 
6145
+           break;
 
6146
+         case B_CONTAINS:
 
6147
+           ret = &octet_contains;
 
6148
+           break;
 
6149
+         case B_MATCHES:
 
6150
+           ret = &octet_matches;
 
6151
+           break;
 
6152
+#ifdef ENABLE_REGEX
 
6153
+         case B_REGEX:
 
6154
+           ret = &octet_regex;
 
6155
+           break;
 
6156
+#endif
 
6157
+         case B_VALUE:
 
6158
+           ret = lookup_rel(relation);
 
6159
+           *comprock = (void **) &octet_cmp;
 
6160
+           break;
 
6161
+       }
 
6162
+       break; /*end of octet */
 
6163
+      case B_ASCIICASEMAP:
 
6164
+       switch (mode) {
 
6165
+       case B_IS:
 
6166
+           ret = &rel_eq;
 
6167
+           *comprock = (void **) &strcasecmp;
 
6168
+           break;
 
6169
+       case B_CONTAINS:
 
6170
+           ret = &ascii_casemap_contains;
 
6171
+           break;
 
6172
+       case B_MATCHES:
 
6173
+           ret = &ascii_casemap_matches;
 
6174
+           break;
 
6175
+#ifdef ENABLE_REGEX
 
6176
+       case B_REGEX:
 
6177
+           /* the ascii-casemap destinction is made during
 
6178
+              the compilation of the regex in verify_regex() */
 
6179
+           ret = &octet_regex;
 
6180
+           break;
 
6181
+#endif
 
6182
+       case B_VALUE:
 
6183
+           ret = lookup_rel(relation);
 
6184
+           *comprock = &strcasecmp;
 
6185
+           break;
 
6186
+       }
 
6187
+       break;/*end of ascii casemap */
 
6188
+      case B_ASCIINUMERIC:
 
6189
+       switch (mode) {
 
6190
+       case B_IS:
 
6191
+           ret = &rel_eq;
 
6192
+           *comprock = (void **) &ascii_numeric_cmp;
 
6193
+           break;
 
6194
+       case B_COUNT:
 
6195
+       case B_VALUE:
 
6196
+           ret = lookup_rel(relation);
 
6197
+           *comprock = (void **) &ascii_numeric_cmp;
 
6198
+           break;
 
6199
+       }
 
6200
+       break;
 
6201
+      }
 
6202
+    return ret;
 
6203
+}
 
6204
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/comparator.h
 
6205
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
6206
+++ b/src/lib-sieve/cmu/libsieve/comparator.h   Sun May 04 16:00:59 2008 +0200
 
6207
@@ -0,0 +1,48 @@
 
6208
+/* comparator.h
 
6209
+ * Larry Greenfield
 
6210
+ * $Id$
 
6211
+ */
 
6212
+/***********************************************************
 
6213
+        Copyright 1999 by Carnegie Mellon University
 
6214
+
 
6215
+                      All Rights Reserved
 
6216
+
 
6217
+Permission to use, copy, modify, and distribute this software and its
 
6218
+documentation for any purpose and without fee is hereby granted,
 
6219
+provided that the above copyright notice appear in all copies and that
 
6220
+both that copyright notice and this permission notice appear in
 
6221
+supporting documentation, and that the name of Carnegie Mellon
 
6222
+University not be used in advertising or publicity pertaining to
 
6223
+distribution of the software without specific, written prior
 
6224
+permission.
 
6225
+
 
6226
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
6227
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
6228
+FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
 
6229
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
6230
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
6231
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 
6232
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
6233
+******************************************************************/
 
6234
+
 
6235
+#ifndef COMPARATOR_H
 
6236
+#define COMPARATOR_H
 
6237
+
 
6238
+#ifdef ENABLE_REGEX
 
6239
+#ifdef HAVE_RX
 
6240
+#include <rxposix.h>
 
6241
+#else
 
6242
+#include <sys/types.h>
 
6243
+#include <regex.h>
 
6244
+#endif
 
6245
+#endif
 
6246
+
 
6247
+/* compares pat to text; returns 1 if it's true, 0 otherwise 
 
6248
+   first arg is text, second arg is pat, third arg is rock */
 
6249
+typedef int comparator_t(const char *, const char *, void *);
 
6250
+
 
6251
+/* returns a pointer to a comparator function given it's name */
 
6252
+comparator_t *lookup_comp(int comp, int mode,
 
6253
+                         int relation, void **rock);
 
6254
+
 
6255
+#endif
 
6256
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/interp.c
 
6257
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
6258
+++ b/src/lib-sieve/cmu/libsieve/interp.c       Sun May 04 16:00:59 2008 +0200
 
6259
@@ -0,0 +1,203 @@
 
6260
+/* interp.c -- sieve script interpretor builder
 
6261
+ * Larry Greenfield
 
6262
+ * $Id$
 
6263
+ */
 
6264
+/***********************************************************
 
6265
+        Copyright 1999 by Carnegie Mellon University
 
6266
+
 
6267
+                      All Rights Reserved
 
6268
+
 
6269
+Permission to use, copy, modify, and distribute this software and its
 
6270
+documentation for any purpose and without fee is hereby granted,
 
6271
+provided that the above copyright notice appear in all copies and that
 
6272
+both that copyright notice and this permission notice appear in
 
6273
+supporting documentation, and that the name of Carnegie Mellon
 
6274
+University not be used in advertising or publicity pertaining to
 
6275
+distribution of the software without specific, written prior
 
6276
+permission.
 
6277
+
 
6278
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
6279
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
6280
+FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
 
6281
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
6282
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
6283
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 
6284
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
6285
+******************************************************************/
 
6286
+
 
6287
+#ifdef HAVE_CONFIG_H
 
6288
+#include <config.h>
 
6289
+#endif
 
6290
+
 
6291
+#include <stdlib.h>
 
6292
+
 
6293
+#include "xmalloc.h"
 
6294
+
 
6295
+#include "sieve_interface.h"
 
6296
+#include "interp.h"
 
6297
+
 
6298
+/* build a sieve interpretor */
 
6299
+int sieve_interp_alloc(sieve_interp_t **interp, void *interp_context)
 
6300
+{
 
6301
+    sieve_interp_t *i;
 
6302
+    static int initonce;
 
6303
+
 
6304
+    if (!initonce) {
 
6305
+       initialize_siev_error_table();
 
6306
+       initonce = 1;
 
6307
+    }
 
6308
+
 
6309
+    *interp = NULL;
 
6310
+    i = (sieve_interp_t *) xmalloc(sizeof(sieve_interp_t));
 
6311
+    if (i == NULL) {
 
6312
+       return SIEVE_NOMEM;
 
6313
+    }
 
6314
+
 
6315
+    i->redirect = i->discard = i->reject = i->fileinto = i->keep = NULL;
 
6316
+    i->getsize = NULL;
 
6317
+    i->getheader = NULL;
 
6318
+    i->getenvelope = NULL;
 
6319
+    i->vacation = NULL;
 
6320
+    i->notify = NULL;
 
6321
+
 
6322
+    i->markflags = NULL;
 
6323
+
 
6324
+    i->interp_context = interp_context;
 
6325
+    i->err = NULL;
 
6326
+
 
6327
+    *interp = i;
 
6328
+    return SIEVE_OK;
 
6329
+}
 
6330
+
 
6331
+static const char *sieve_extensions = "fileinto reject envelope vacation"
 
6332
+                                      " imapflags notify subaddress relational"
 
6333
+                                      " comparator-i;ascii-numeric"
 
6334
+#ifdef ENABLE_REGEX
 
6335
+" regex";
 
6336
+#else
 
6337
+"";
 
6338
+#endif /* ENABLE_REGEX */
 
6339
+
 
6340
+const char *sieve_listextensions(void)
 
6341
+{
 
6342
+    return sieve_extensions;
 
6343
+}
 
6344
+
 
6345
+int sieve_interp_free(sieve_interp_t **interp)
 
6346
+{
 
6347
+    free(*interp);
 
6348
+    
 
6349
+    return SIEVE_OK;
 
6350
+}
 
6351
+
 
6352
+/* add the callbacks */
 
6353
+int sieve_register_redirect(sieve_interp_t *interp, sieve_callback *f)
 
6354
+{
 
6355
+    interp->redirect = f;
 
6356
+
 
6357
+    return SIEVE_OK;
 
6358
+}
 
6359
+
 
6360
+int sieve_register_discard(sieve_interp_t *interp, sieve_callback *f)
 
6361
+{
 
6362
+    interp->discard = f;
 
6363
+
 
6364
+    return SIEVE_OK;
 
6365
+}
 
6366
+
 
6367
+int sieve_register_reject(sieve_interp_t *interp, sieve_callback *f)
 
6368
+{
 
6369
+    interp->reject = f;
 
6370
+
 
6371
+    return SIEVE_OK;
 
6372
+}
 
6373
+
 
6374
+int sieve_register_fileinto(sieve_interp_t *interp, sieve_callback *f)
 
6375
+{
 
6376
+    interp->fileinto = f;
 
6377
+
 
6378
+    return SIEVE_OK;
 
6379
+}
 
6380
+
 
6381
+int sieve_register_keep(sieve_interp_t *interp, sieve_callback *f)
 
6382
+{
 
6383
+    interp->keep = f;
 
6384
 
6385
+    return SIEVE_OK;
 
6386
+}
 
6387
+
 
6388
+static char *default_markflags[] = { "\\flagged" };
 
6389
+static sieve_imapflags_t default_mark = { default_markflags, 1 };
 
6390
+
 
6391
+int sieve_register_imapflags(sieve_interp_t *interp, sieve_imapflags_t *mark)
 
6392
+{
 
6393
+    interp->markflags =
 
6394
+       (mark && mark->flag && mark->nflags) ? mark : &default_mark;
 
6395
+
 
6396
+    return SIEVE_OK;
 
6397
+}
 
6398
+
 
6399
+int sieve_register_notify(sieve_interp_t *interp, sieve_callback *f)
 
6400
+{
 
6401
+    interp->notify = f;
 
6402
 
6403
+    return SIEVE_OK;
 
6404
+}
 
6405
+
 
6406
+/* add the callbacks for messages. again, undefined if used after
 
6407
+   sieve_script_parse */
 
6408
+int sieve_register_size(sieve_interp_t *interp, sieve_get_size *f)
 
6409
+{
 
6410
+    interp->getsize = f;
 
6411
+    return SIEVE_OK;
 
6412
+}
 
6413
+
 
6414
+int sieve_register_header(sieve_interp_t *interp, sieve_get_header *f)
 
6415
+{
 
6416
+    interp->getheader = f;
 
6417
+    return SIEVE_OK;
 
6418
+}
 
6419
+
 
6420
+int sieve_register_envelope(sieve_interp_t *interp, sieve_get_envelope *f)
 
6421
+{
 
6422
+    interp->getenvelope = f;
 
6423
+    return SIEVE_OK;
 
6424
+}
 
6425
+
 
6426
+int sieve_register_vacation(sieve_interp_t *interp, sieve_vacation_t *v)
 
6427
+{
 
6428
+    if (!interp->getenvelope) {
 
6429
+       return SIEVE_NOT_FINALIZED; /* we need envelope for vacation! */
 
6430
+    }
 
6431
+
 
6432
+    if (v->min_response == 0) v->min_response = 3;
 
6433
+    if (v->max_response == 0) v->max_response = 90;
 
6434
+    if (v->min_response < 0 || v->max_response < 7 || !v->autorespond
 
6435
+       || !v->send_response) {
 
6436
+       return SIEVE_FAIL;
 
6437
+    }
 
6438
+
 
6439
+    interp->vacation = v;
 
6440
+    return SIEVE_OK;
 
6441
+}
 
6442
+
 
6443
+int sieve_register_parse_error(sieve_interp_t *interp, sieve_parse_error *f)
 
6444
+{
 
6445
+    interp->err = f;
 
6446
+    return SIEVE_OK;
 
6447
+}
 
6448
+
 
6449
+int sieve_register_execute_error(sieve_interp_t *interp, sieve_execute_error *f)
 
6450
+{
 
6451
+    interp->execute_err = f;
 
6452
+    return SIEVE_OK;
 
6453
+}
 
6454
+
 
6455
+int interp_verify(sieve_interp_t *i)
 
6456
+{
 
6457
+    if (i->redirect && i->keep && i->getsize && i->getheader) {
 
6458
+       return SIEVE_OK;
 
6459
+    } else {
 
6460
+       return SIEVE_NOT_FINALIZED;
 
6461
+    }
 
6462
+}
 
6463
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/interp.h
 
6464
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
6465
+++ b/src/lib-sieve/cmu/libsieve/interp.h       Sun May 04 16:00:59 2008 +0200
 
6466
@@ -0,0 +1,56 @@
 
6467
+/* interp.h -- interpretor definition
 
6468
+ * Larry Greenfield
 
6469
+ * $Id$
 
6470
+ */
 
6471
+/***********************************************************
 
6472
+        Copyright 1999 by Carnegie Mellon University
 
6473
+
 
6474
+                      All Rights Reserved
 
6475
+
 
6476
+Permission to use, copy, modify, and distribute this software and its
 
6477
+documentation for any purpose and without fee is hereby granted,
 
6478
+provided that the above copyright notice appear in all copies and that
 
6479
+both that copyright notice and this permission notice appear in
 
6480
+supporting documentation, and that the name of Carnegie Mellon
 
6481
+University not be used in advertising or publicity pertaining to
 
6482
+distribution of the software without specific, written prior
 
6483
+permission.
 
6484
+
 
6485
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
6486
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
6487
+FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
 
6488
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
6489
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
6490
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 
6491
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
6492
+*****************************************************************/
 
6493
+
 
6494
+#ifndef SIEVE_INTERP_H
 
6495
+#define SIEVE_INTERP_H
 
6496
+
 
6497
+#include "sieve_interface.h"
 
6498
+
 
6499
+struct sieve_interp {
 
6500
+    /* standard callbacks for actions */
 
6501
+    sieve_callback *redirect, *discard, *reject, *fileinto, *keep;
 
6502
+    sieve_callback *notify;
 
6503
+    sieve_vacation_t *vacation;
 
6504
+
 
6505
+    sieve_get_size *getsize;
 
6506
+    sieve_get_header *getheader;
 
6507
+    sieve_get_envelope *getenvelope;
 
6508
+
 
6509
+    sieve_parse_error *err;
 
6510
+
 
6511
+    /* site-specific imapflags for mark/unmark */
 
6512
+    sieve_imapflags_t *markflags;
 
6513
+
 
6514
+    sieve_execute_error *execute_err;
 
6515
+
 
6516
+    /* context to pass along */
 
6517
+    void *interp_context;
 
6518
+};
 
6519
+
 
6520
+int interp_verify(sieve_interp_t *interp);
 
6521
+
 
6522
+#endif
 
6523
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/message.c
 
6524
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
6525
+++ b/src/lib-sieve/cmu/libsieve/message.c      Sun May 04 16:00:59 2008 +0200
 
6526
@@ -0,0 +1,580 @@
 
6527
+/* message.c -- message parsing functions
 
6528
+ * Larry Greenfield
 
6529
+ * $Id$
 
6530
+ */
 
6531
+/***********************************************************
 
6532
+        Copyright 1999 by Carnegie Mellon University
 
6533
+
 
6534
+                      All Rights Reserved
 
6535
+
 
6536
+Permission to use, copy, modify, and distribute this software and its
 
6537
+documentation for any purpose and without fee is hereby granted,
 
6538
+provided that the above copyright notice appear in all copies and that
 
6539
+both that copyright notice and this permission notice appear in
 
6540
+supporting documentation, and that the name of Carnegie Mellon
 
6541
+University not be used in advertising or publicity pertaining to
 
6542
+distribution of the software without specific, written prior
 
6543
+permission.
 
6544
+
 
6545
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
6546
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
6547
+FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
 
6548
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
6549
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
6550
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 
6551
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
6552
+******************************************************************/
 
6553
+
 
6554
+#ifdef HAVE_CONFIG_H
 
6555
+#include <config.h>
 
6556
+#endif
 
6557
+
 
6558
+#include <stdlib.h>
 
6559
+#include <unistd.h>
 
6560
+#include <sys/mman.h>
 
6561
+#include <sys/stat.h>
 
6562
+#include <sys/types.h>
 
6563
+#include <sys/stat.h>
 
6564
+#include <fcntl.h>
 
6565
+#include <string.h>
 
6566
+
 
6567
+#include "sieve_interface.h"
 
6568
+#include "interp.h"
 
6569
+#include "message.h"
 
6570
+#include "parseaddr.h"
 
6571
+#include "xmalloc.h"
 
6572
+
 
6573
+/* reject message m with message msg
 
6574
+ *
 
6575
+ * incompatible with: fileinto, redirect
 
6576
+ */
 
6577
+int do_reject(action_list_t *a, const char *msg)
 
6578
+{
 
6579
+    action_list_t *b = NULL;
 
6580
+
 
6581
+    /* see if this conflicts with any previous actions taken on this message */
 
6582
+    while (a != NULL) {
 
6583
+       b = a;
 
6584
+       if (a->a == ACTION_FILEINTO ||
 
6585
+           a->a == ACTION_KEEP ||
 
6586
+           a->a == ACTION_REDIRECT ||
 
6587
+           a->a == ACTION_REJECT ||
 
6588
+           a->a == ACTION_VACATION ||
 
6589
+           a->a == ACTION_SETFLAG ||
 
6590
+           a->a == ACTION_ADDFLAG ||
 
6591
+           a->a == ACTION_REMOVEFLAG ||
 
6592
+           a->a == ACTION_MARK ||
 
6593
+           a->a == ACTION_UNMARK
 
6594
+           )
 
6595
+           return SIEVE_RUN_ERROR;
 
6596
+       a = a->next;
 
6597
+    }
 
6598
+
 
6599
+    /* add to the action list */
 
6600
+    a = (action_list_t *) xmalloc(sizeof(action_list_t));
 
6601
+    if (a == NULL)
 
6602
+       return SIEVE_NOMEM;
 
6603
+    a->a = ACTION_REJECT;
 
6604
+    a->u.rej.msg = msg;
 
6605
+    b->next = a;
 
6606
+    a->next =  NULL;
 
6607
+    return 0;
 
6608
+}
 
6609
+
 
6610
+/* fileinto message m into mailbox 
 
6611
+ *
 
6612
+ * incompatible with: reject
 
6613
+ */
 
6614
+int do_fileinto(action_list_t *a, const char *mbox,
 
6615
+               sieve_imapflags_t *imapflags)
 
6616
+{
 
6617
+    action_list_t *b = NULL;
 
6618
+
 
6619
+    /* see if this conflicts with any previous actions taken on this message */
 
6620
+    while (a != NULL) {
 
6621
+       b = a;
 
6622
+       if (a->a == ACTION_REJECT)
 
6623
+           return SIEVE_RUN_ERROR;
 
6624
+       a = a->next;
 
6625
+    }
 
6626
+
 
6627
+    /* add to the action list */
 
6628
+    a = (action_list_t *) xmalloc(sizeof(action_list_t));
 
6629
+    if (a == NULL)
 
6630
+       return SIEVE_NOMEM;
 
6631
+    a->a = ACTION_FILEINTO;
 
6632
+    a->u.fil.mailbox = mbox;
 
6633
+    a->u.fil.imapflags = imapflags;
 
6634
+    b->next = a;
 
6635
+    a->next = NULL;
 
6636
+    return 0;
 
6637
+}
 
6638
+
 
6639
+/* redirect message m to to addr
 
6640
+ *
 
6641
+ * incompatible with: reject
 
6642
+ */
 
6643
+int do_redirect(action_list_t *a, const char *addr)
 
6644
+{
 
6645
+    action_list_t *b = NULL;
 
6646
+
 
6647
+    /* xxx we should validate addr */
 
6648
+
 
6649
+    /* see if this conflicts with any previous actions taken on this message */
 
6650
+    while (a != NULL) {
 
6651
+       b = a;
 
6652
+       if (a->a == ACTION_REJECT)
 
6653
+           return SIEVE_RUN_ERROR;
 
6654
+       a = a->next;
 
6655
+    }
 
6656
+
 
6657
+    /* add to the action list */
 
6658
+    a = (action_list_t *) xmalloc(sizeof(action_list_t));
 
6659
+    if (a == NULL)
 
6660
+       return SIEVE_NOMEM;
 
6661
+    a->a = ACTION_REDIRECT;
 
6662
+    a->u.red.addr = addr;
 
6663
+    a->next = NULL;
 
6664
+    b->next = a;
 
6665
+    return 0;
 
6666
+}
 
6667
+
 
6668
+/* keep message
 
6669
+ *
 
6670
+ * incompatible with: reject
 
6671
+ */
 
6672
+int do_keep(action_list_t *a, sieve_imapflags_t *imapflags)
 
6673
+{
 
6674
+    action_list_t *b = NULL;
 
6675
+
 
6676
+    /* see if this conflicts with any previous actions taken on this message */
 
6677
+    while (a != NULL) {
 
6678
+       b = a;
 
6679
+       if (a->a == ACTION_REJECT)
 
6680
+           return SIEVE_RUN_ERROR;
 
6681
+       if (a->a == ACTION_KEEP) /* don't bother doing it twice */
 
6682
+           return 0;
 
6683
+       a = a->next;
 
6684
+    }
 
6685
+
 
6686
+    /* add to the action list */
 
6687
+    a = (action_list_t *) xmalloc(sizeof(action_list_t));
 
6688
+    if (a == NULL)
 
6689
+       return SIEVE_NOMEM;
 
6690
+    a->a = ACTION_KEEP;
 
6691
+    a->u.keep.imapflags = imapflags;
 
6692
+    a->next = NULL;
 
6693
+    b->next = a;
 
6694
+    return 0;
 
6695
+}
 
6696
+
 
6697
+/* discard message m
 
6698
+ *
 
6699
+ * incompatible with: nothing---it doesn't cancel any actions
 
6700
+ */
 
6701
+int do_discard(action_list_t *a)
 
6702
+{
 
6703
+    action_list_t *b = NULL;
 
6704
+
 
6705
+    /* see if this conflicts with any previous actions taken on this message */
 
6706
+    while (a != NULL) {
 
6707
+       b = a;
 
6708
+       if (a->a == ACTION_DISCARD) /* don't bother doing twice */
 
6709
+           return 0;
 
6710
+       a = a->next;
 
6711
+    }
 
6712
+
 
6713
+    /* add to the action list */
 
6714
+    a = (action_list_t *) xmalloc(sizeof(action_list_t));
 
6715
+    if (a == NULL)
 
6716
+       return SIEVE_NOMEM;
 
6717
+    a->a = ACTION_DISCARD;
 
6718
+    a->next = NULL;
 
6719
+    b->next = a;
 
6720
+    return 0;
 
6721
+}
 
6722
+
 
6723
+int do_vacation(action_list_t *a, char *addr, char *fromaddr,
 
6724
+               char *subj, const char *msg, int days,
 
6725
+               int mime)
 
6726
+{
 
6727
+    action_list_t *b = NULL;
 
6728
+
 
6729
+    /* see if this conflicts with any previous actions taken on this message */
 
6730
+    while (a != NULL) {
 
6731
+       b = a;
 
6732
+       if (a->a == ACTION_REJECT ||
 
6733
+           a->a == ACTION_VACATION) /* vacation can't be used twice */
 
6734
+           return SIEVE_RUN_ERROR;
 
6735
+       a = a->next;
 
6736
+    }
 
6737
+
 
6738
+    /* add to the action list */
 
6739
+    a = (action_list_t *) xmalloc(sizeof(action_list_t));
 
6740
+    if (a == NULL)
 
6741
+       return SIEVE_NOMEM;
 
6742
+    a->a = ACTION_VACATION;
 
6743
+    a->u.vac.send.addr = addr;
 
6744
+    a->u.vac.send.fromaddr = fromaddr;
 
6745
+    a->u.vac.send.subj = subj; /* user specified subject */
 
6746
+    a->u.vac.send.msg = msg;
 
6747
+    a->u.vac.send.mime = mime;
 
6748
+    a->u.vac.autoresp.days = days;
 
6749
+    a->next = NULL;
 
6750
+    b->next = a;
 
6751
+    return 0;
 
6752
+}
 
6753
+
 
6754
+/* setflag f on message m
 
6755
+ *
 
6756
+ * incompatible with: reject
 
6757
+ */
 
6758
+int do_setflag(action_list_t *a, const char *flag)
 
6759
+{
 
6760
+    action_list_t *b = NULL;
 
6761
 
6762
+    /* see if this conflicts with any previous actions taken on this message */
 
6763
+    while (a != NULL) {
 
6764
+       b = a;
 
6765
+       if (a->a == ACTION_REJECT)
 
6766
+           return SIEVE_RUN_ERROR;
 
6767
+       a = a->next;
 
6768
+    }
 
6769
 
6770
+    /* add to the action list */
 
6771
+    a = (action_list_t *) xmalloc(sizeof(action_list_t));
 
6772
+    if (a == NULL)
 
6773
+       return SIEVE_NOMEM;
 
6774
+    a->a = ACTION_SETFLAG;
 
6775
+    a->u.fla.flag = flag;
 
6776
+    b->next = a;
 
6777
+    a->next = NULL;
 
6778
+    return 0;
 
6779
+}
 
6780
+
 
6781
+/* addflag f on message m
 
6782
+ *
 
6783
+ * incompatible with: reject
 
6784
+ */
 
6785
+int do_addflag(action_list_t *a, const char *flag)
 
6786
+{
 
6787
+    action_list_t *b = NULL;
 
6788
 
6789
+    /* see if this conflicts with any previous actions taken on this message */
 
6790
+    while (a != NULL) {
 
6791
+       b = a;
 
6792
+       if (a->a == ACTION_REJECT)
 
6793
+           return SIEVE_RUN_ERROR;
 
6794
+       a = a->next;
 
6795
+    }
 
6796
 
6797
+    /* add to the action list */
 
6798
+    a = (action_list_t *) xmalloc(sizeof(action_list_t));
 
6799
+    if (a == NULL)
 
6800
+       return SIEVE_NOMEM;
 
6801
+    a->a = ACTION_ADDFLAG;
 
6802
+    a->u.fla.flag = flag;
 
6803
+    b->next = a;
 
6804
+    a->next = NULL;
 
6805
+    return 0;
 
6806
+}
 
6807
+
 
6808
+/* removeflag f on message m
 
6809
+ *
 
6810
+ * incompatible with: reject
 
6811
+ */
 
6812
+int do_removeflag(action_list_t *a, const char *flag)
 
6813
+{
 
6814
+    action_list_t *b = NULL;
 
6815
 
6816
+    /* see if this conflicts with any previous actions taken on this message */
 
6817
+    while (a != NULL) {
 
6818
+       b = a;
 
6819
+       if (a->a == ACTION_REJECT)
 
6820
+           return SIEVE_RUN_ERROR;
 
6821
+       a = a->next;
 
6822
+    }
 
6823
 
6824
+    /* add to the action list */
 
6825
+    a = (action_list_t *) xmalloc(sizeof(action_list_t));
 
6826
+    if (a == NULL)
 
6827
+       return SIEVE_NOMEM;
 
6828
+    a->a = ACTION_REMOVEFLAG;
 
6829
+    a->u.fla.flag = flag;
 
6830
+    b->next = a;
 
6831
+    a->next = NULL;
 
6832
+    return 0;
 
6833
+}
 
6834
+
 
6835
+
 
6836
+/* mark message m
 
6837
+ *
 
6838
+ * incompatible with: reject
 
6839
+ */
 
6840
+int do_mark(action_list_t *a)
 
6841
+{
 
6842
+    action_list_t *b = NULL;
 
6843
 
6844
+    /* see if this conflicts with any previous actions taken on this message */
 
6845
+    while (a != NULL) {
 
6846
+       b = a;
 
6847
+       if (a->a == ACTION_REJECT)
 
6848
+           return SIEVE_RUN_ERROR;
 
6849
+       a = a->next;
 
6850
+    }
 
6851
 
6852
+    /* add to the action list */
 
6853
+    a = (action_list_t *) xmalloc(sizeof(action_list_t));
 
6854
+    if (a == NULL)
 
6855
+       return SIEVE_NOMEM;
 
6856
+    a->a = ACTION_MARK;
 
6857
+    b->next = a;
 
6858
+    a->next = NULL;
 
6859
+    return 0;
 
6860
+}
 
6861
+
 
6862
+
 
6863
+/* unmark message m
 
6864
+ *
 
6865
+ * incompatible with: reject
 
6866
+ */
 
6867
+int do_unmark(action_list_t *a)
 
6868
+{
 
6869
+
 
6870
+    action_list_t *b = NULL;
 
6871
+    /* see if this conflicts with any previous actions taken on this message */
 
6872
+    while (a != NULL) {
 
6873
+       b = a;
 
6874
+       if (a->a == ACTION_REJECT)
 
6875
+           return SIEVE_RUN_ERROR;
 
6876
+       a = a->next;
 
6877
+    }
 
6878
 
6879
+    /* add to the action list */
 
6880
+    a = (action_list_t *) xmalloc(sizeof(action_list_t));
 
6881
+    if (a == NULL)
 
6882
+       return SIEVE_NOMEM;
 
6883
+    a->a = ACTION_UNMARK;
 
6884
+    b->next = a;
 
6885
+    a->next = NULL;
 
6886
+    return 0;
 
6887
+}
 
6888
+
 
6889
+/* notify
 
6890
+ *
 
6891
+ * incompatible with: none
 
6892
+ */
 
6893
+int do_notify(notify_list_t *a, const char *id,
 
6894
+             const char *method, const char **options,
 
6895
+             const char *priority, const char *message)
 
6896
+{
 
6897
+    notify_list_t *b = NULL;
 
6898
+
 
6899
+    /* find the end of the notify list */
 
6900
+    while (a != NULL) {
 
6901
+       b = a;
 
6902
+       a = a->next;
 
6903
+    }
 
6904
+
 
6905
+    /* add to the notify list */
 
6906
+    a = (notify_list_t *) xmalloc(sizeof(notify_list_t));
 
6907
+    if (a == NULL)
 
6908
+       return SIEVE_NOMEM;
 
6909
+
 
6910
+    b->next = a;
 
6911
+    a->isactive = 1;
 
6912
+    a->id = id;
 
6913
+    a->method = method;
 
6914
+    a->options = options;
 
6915
+    a->priority = priority;
 
6916
+    a->message = message;
 
6917
+    a->next = NULL;
 
6918
+    return 0;
 
6919
+}
 
6920
+
 
6921
+/* denotify
 
6922
+ *
 
6923
+ * incomaptible with: none
 
6924
+ */
 
6925
+int do_denotify(notify_list_t *n, comparator_t *comp, const void *pat,
 
6926
+               void *comprock, const char *priority)
 
6927
+{
 
6928
+    while (n != NULL) {
 
6929
+       if (n->isactive && 
 
6930
+           (!priority || !strcasecmp(n->priority, priority)) &&
 
6931
+           (!comp || (n->id && comp(n->id, pat, comprock)))) {
 
6932
+           n->isactive = 0;
 
6933
+       }
 
6934
+       n = n->next;
 
6935
+    }
 
6936
+
 
6937
+    return 0;
 
6938
+}
 
6939
+
 
6940
+
 
6941
+
 
6942
+/* given a header, extract an address out of it.  if marker points to NULL,
 
6943
+   extract the first address.  otherwise, it's an index into the header to
 
6944
+   say where to start extracting */
 
6945
+struct addr_marker {
 
6946
+    struct address *where;
 
6947
+    char *freeme;
 
6948
+};
 
6949
+
 
6950
+int parse_address(const char *header, void **data, void **marker)
 
6951
+{
 
6952
+    struct addr_marker *am = (struct addr_marker *) *marker;
 
6953
+
 
6954
+    parseaddr_list(header, (struct address **) data);
 
6955
+    am = (void *) xmalloc(sizeof(struct addr_marker));
 
6956
+    am->where = *data;
 
6957
+    am->freeme = NULL;
 
6958
+    *marker = am;
 
6959
+    return SIEVE_OK;
 
6960
+}
 
6961
+
 
6962
+char *get_address(address_part_t addrpart,
 
6963
+                 void **data __attr_unused__,
 
6964
+                 void **marker,
 
6965
+                 int canon_domain)
 
6966
+{
 
6967
+    char *ret = NULL;
 
6968
+    struct address *a;
 
6969
+    struct addr_marker *am = *marker;
 
6970
+
 
6971
+    a = am->where;
 
6972
+    if (am->freeme) {
 
6973
+       free(am->freeme);
 
6974
+       am->freeme = NULL;
 
6975
+    }
 
6976
+
 
6977
+    if (a == NULL) {
 
6978
+       ret = NULL;
 
6979
+    } else {
 
6980
+       if (canon_domain && a->domain)
 
6981
+           lcase(a->domain);
 
6982
+
 
6983
+       switch (addrpart) { 
 
6984
+       case ADDRESS_ALL:
 
6985
+#define U_DOMAIN "unspecified-domain"
 
6986
+#define U_USER "unknown-user"
 
6987
+           if (a->mailbox || a->domain) {
 
6988
+               char *m = a->mailbox ? a->mailbox : U_USER;
 
6989
+               char *d = a->domain ? a->domain : U_DOMAIN;
 
6990
+               am->freeme = (char *) xmalloc(strlen(m) + strlen(d) + 2);
 
6991
+
 
6992
+               sprintf(am->freeme, "%s@%s", m, d);
 
6993
+               ret = am->freeme;
 
6994
+           } else {
 
6995
+               ret = NULL;
 
6996
+           }
 
6997
+           break;
 
6998
+
 
6999
+       case ADDRESS_LOCALPART:
 
7000
+           ret = a->mailbox;
 
7001
+           break;
 
7002
+           
 
7003
+       case ADDRESS_DOMAIN:
 
7004
+           ret = a->domain;
 
7005
+           break;
 
7006
+
 
7007
+       case ADDRESS_USER:
 
7008
+           if (a->mailbox) {
 
7009
+               char *p = strchr(a->mailbox, '+');
 
7010
+               int len = p ? p - a->mailbox : (int)strlen(a->mailbox);
 
7011
+
 
7012
+               am->freeme = (char *) xmalloc(len + 1);
 
7013
+               strncpy(am->freeme, a->mailbox, len);
 
7014
+               am->freeme[len] = '\0';
 
7015
+               ret = am->freeme;
 
7016
+           } else {
 
7017
+               ret = NULL;
 
7018
+           }
 
7019
+           break;
 
7020
+
 
7021
+       case ADDRESS_DETAIL:
 
7022
+           if (a->mailbox)
 
7023
+           {       
 
7024
+               char *p = strchr(a->mailbox, '+');
 
7025
+               ret = (p ? p + 1 : NULL);
 
7026
+           }
 
7027
+           else
 
7028
+           {
 
7029
+               ret = NULL;
 
7030
+           }
 
7031
+           break;
 
7032
+       }
 
7033
+       a = a->next;
 
7034
+       am->where = a;
 
7035
+    }
 
7036
+    *marker = am;
 
7037
+    return ret;
 
7038
+}
 
7039
+
 
7040
+int free_address(void **data, void **marker)
 
7041
+{
 
7042
+    struct addr_marker *am = (struct addr_marker *) *marker;
 
7043
+
 
7044
+    if (*data)
 
7045
+       parseaddr_free((struct address *) *data);
 
7046
+    *data = NULL;
 
7047
+    if (am->freeme) free(am->freeme);
 
7048
+    free(am);
 
7049
+    *marker = NULL;
 
7050
+    return SIEVE_OK;
 
7051
+}
 
7052
+
 
7053
+notify_list_t *new_notify_list(void)    
 
7054
+{
 
7055
+    notify_list_t *ret = xmalloc(sizeof(notify_list_t));
 
7056
+
 
7057
+    if (ret != NULL) {
 
7058
+       ret->isactive = 0;
 
7059
+       ret->id       = NULL;
 
7060
+       ret->method   = NULL;
 
7061
+       ret->options  = NULL;
 
7062
+       ret->priority = NULL;
 
7063
+       ret->message  = NULL;
 
7064
+       ret->next     = NULL;
 
7065
+    }
 
7066
+    return ret;
 
7067
+}
 
7068
+
 
7069
+void free_notify_list(notify_list_t *n)
 
7070
+{
 
7071
+    while (n) {
 
7072
+       notify_list_t *b = n->next;
 
7073
+       free(n->options); /* strings live in bytecode, only free the array */
 
7074
+       free(n);
 
7075
+       n = b;
 
7076
+    }
 
7077
+}
 
7078
+
 
7079
+action_list_t *new_action_list(void)
 
7080
+{
 
7081
+    action_list_t *ret = xmalloc(sizeof(action_list_t));
 
7082
+
 
7083
+    if (ret != NULL) {
 
7084
+       ret->a = ACTION_NONE;
 
7085
+       ret->param = NULL;
 
7086
+       ret->next = NULL;
 
7087
+    }
 
7088
+    return ret;
 
7089
+}
 
7090
+
 
7091
+void free_action_list(action_list_t *a)
 
7092
+{
 
7093
+    while (a) {
 
7094
+       action_list_t *b = a->next;
 
7095
+
 
7096
+       if(a->a == ACTION_VACATION) {
 
7097
+           if(a->u.vac.send.subj) free(a->u.vac.send.subj);
 
7098
+           if(a->u.vac.send.addr) free(a->u.vac.send.addr);
 
7099
+           if(a->u.vac.send.fromaddr) free(a->u.vac.send.fromaddr);
 
7100
+       }
 
7101
+
 
7102
+       free(a);
 
7103
+       a = b;
 
7104
+    }
 
7105
+}
 
7106
+
 
7107
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/message.h
 
7108
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
7109
+++ b/src/lib-sieve/cmu/libsieve/message.h      Sun May 04 16:00:59 2008 +0200
 
7110
@@ -0,0 +1,140 @@
 
7111
+/* message.h
 
7112
+ * Larry Greenfield
 
7113
+ * $Id$
 
7114
+ */
 
7115
+/***********************************************************
 
7116
+        Copyright 1999 by Carnegie Mellon University
 
7117
+
 
7118
+                      All Rights Reserved
 
7119
+
 
7120
+Permission to use, copy, modify, and distribute this software and its
 
7121
+documentation for any purpose and without fee is hereby granted,
 
7122
+provided that the above copyright notice appear in all copies and that
 
7123
+both that copyright notice and this permission notice appear in
 
7124
+supporting documentation, and that the name of Carnegie Mellon
 
7125
+University not be used in advertising or publicity pertaining to
 
7126
+distribution of the software without specific, written prior
 
7127
+permission.
 
7128
+
 
7129
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
7130
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
7131
+FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
 
7132
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
7133
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
7134
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 
7135
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
7136
+******************************************************************/
 
7137
+
 
7138
+#ifndef MESSAGE_H
 
7139
+#define MESSAGE_H
 
7140
+
 
7141
+#include "sieve_interface.h"   /* for action contexts */
 
7142
+#include "tree.h"              /* for stringlist_t */
 
7143
+
 
7144
+typedef struct Action action_list_t;
 
7145
+
 
7146
+typedef enum {
 
7147
+    ACTION_NULL = -1,
 
7148
+    ACTION_NONE = 0,
 
7149
+    ACTION_REJECT,
 
7150
+    ACTION_FILEINTO,
 
7151
+    ACTION_KEEP,
 
7152
+    ACTION_REDIRECT,
 
7153
+    ACTION_DISCARD,
 
7154
+    ACTION_VACATION,
 
7155
+    ACTION_SETFLAG,
 
7156
+    ACTION_ADDFLAG,
 
7157
+    ACTION_REMOVEFLAG,
 
7158
+    ACTION_MARK,
 
7159
+    ACTION_UNMARK,
 
7160
+    ACTION_NOTIFY,
 
7161
+    ACTION_DENOTIFY
 
7162
+} action_t;
 
7163
+
 
7164
+/* information */
 
7165
+action_list_t *new_action_list(void);
 
7166
+void free_action_list(action_list_t *actions);
 
7167
+
 
7168
+/* invariant: always have a dummy element when free_action_list, param
 
7169
+   and vac_subj are freed.  none of the others are automatically freed.
 
7170
+
 
7171
+   the do_action() functions should copy param */
 
7172
+struct Action {
 
7173
+    action_t a;
 
7174
+    union {
 
7175
+       sieve_reject_context_t rej;
 
7176
+       sieve_fileinto_context_t fil;
 
7177
+       sieve_keep_context_t keep;
 
7178
+       sieve_redirect_context_t red;
 
7179
+       struct {
 
7180
+           /* addr, fromaddr, subj - freed! */
 
7181
+           sieve_send_response_context_t send;
 
7182
+           sieve_autorespond_context_t autoresp;
 
7183
+       } vac;
 
7184
+       struct {
 
7185
+           const char *flag;
 
7186
+       } fla;
 
7187
+    } u;
 
7188
+    char *param;               /* freed! */
 
7189
+    struct Action *next;
 
7190
+    char *vac_subj;            /* freed! */
 
7191
+    char *vac_msg;
 
7192
+    int vac_days;
 
7193
+};
 
7194
+
 
7195
+typedef struct notify_list_s {
 
7196
+    int isactive;
 
7197
+    const char *id;
 
7198
+    const char *method;
 
7199
+    const char **options;
 
7200
+    const char *priority;
 
7201
+    const char *message;
 
7202
+    struct notify_list_s *next;
 
7203
+} notify_list_t;
 
7204
+
 
7205
+/* header parsing */
 
7206
+typedef enum {
 
7207
+    ADDRESS_ALL,
 
7208
+    ADDRESS_LOCALPART,
 
7209
+    ADDRESS_DOMAIN,
 
7210
+    ADDRESS_USER,
 
7211
+    ADDRESS_DETAIL
 
7212
+} address_part_t;
 
7213
+
 
7214
+int parse_address(const char *header, void **data, void **marker);
 
7215
+char *get_address(address_part_t addrpart, void **data, void **marker,
 
7216
+                 int canon_domain);
 
7217
+int free_address(void **data, void **marker);
 
7218
+notify_list_t *new_notify_list(void);
 
7219
+void free_notify_list(notify_list_t *n);
 
7220
+
 
7221
+/* actions; return negative on failure.
 
7222
+ * these don't actually perform the actions, they just add it to the
 
7223
+ * action list */
 
7224
+int do_reject(action_list_t *m, const char *msg);
 
7225
+int do_fileinto(action_list_t *m, const char *mbox,
 
7226
+               sieve_imapflags_t *imapflags);
 
7227
+int do_redirect(action_list_t *m, const char *addr);
 
7228
+int do_keep(action_list_t *m, sieve_imapflags_t *imapflags);
 
7229
+int do_discard(action_list_t *m);
 
7230
+int do_vacation(action_list_t *m, char *addr, char *fromaddr,
 
7231
+               char *subj, const char *msg, int days, int mime);
 
7232
+int do_setflag(action_list_t *m, const char *flag);
 
7233
+int do_addflag(action_list_t *m, const char *flag);
 
7234
+int do_removeflag(action_list_t *m, const char *flag);
 
7235
+int do_mark(action_list_t *m);
 
7236
+int do_unmark(action_list_t *m);
 
7237
+int do_notify(notify_list_t *n, const char *id,
 
7238
+             const char *method, const char **options,
 
7239
+             const char *priority, const char *message);
 
7240
+int do_denotify(notify_list_t *n, comparator_t *comp, const void *pat,
 
7241
+               void *comprock, const char *priority);
 
7242
+
 
7243
+/* execute some bytecode */
 
7244
+int sieve_eval_bc(sieve_interp_t *i, const void *bc_in, unsigned int bc_len,
 
7245
+                 void *m, sieve_imapflags_t * imapflags,
 
7246
+                 action_list_t *actions,
 
7247
+                 notify_list_t *notify_list,
 
7248
+                 const char **errmsg);
 
7249
+
 
7250
+#endif
 
7251
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/parseaddr.c
 
7252
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
7253
+++ b/src/lib-sieve/cmu/libsieve/parseaddr.c    Sun May 04 16:00:59 2008 +0200
 
7254
@@ -0,0 +1,370 @@
 
7255
+/* parseaddr.c -- RFC 822 address parser
 
7256
+ * $Id$
 
7257
+ *
 
7258
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
 
7259
+ *
 
7260
+ * Redistribution and use in source and binary forms, with or without
 
7261
+ * modification, are permitted provided that the following conditions
 
7262
+ * are met:
 
7263
+ *
 
7264
+ * 1. Redistributions of source code must retain the above copyright
 
7265
+ *    notice, this list of conditions and the following disclaimer. 
 
7266
+ *
 
7267
+ * 2. Redistributions in binary form must reproduce the above copyright
 
7268
+ *    notice, this list of conditions and the following disclaimer in
 
7269
+ *    the documentation and/or other materials provided with the
 
7270
+ *    distribution.
 
7271
+ *
 
7272
+ * 3. The name "Carnegie Mellon University" must not be used to
 
7273
+ *    endorse or promote products derived from this software without
 
7274
+ *    prior written permission. For permission or any other legal
 
7275
+ *    details, please contact  
 
7276
+ *      Office of Technology Transfer
 
7277
+ *      Carnegie Mellon University
 
7278
+ *      5000 Forbes Avenue
 
7279
+ *      Pittsburgh, PA  15213-3890
 
7280
+ *      (412) 268-4387, fax: (412) 268-7395
 
7281
+ *      tech-transfer@andrew.cmu.edu
 
7282
+ *
 
7283
+ * 4. Redistributions of any form whatsoever must retain the following
 
7284
+ *    acknowledgment:
 
7285
+ *    "This product includes software developed by Computing Services
 
7286
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
 
7287
+ *
 
7288
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
7289
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 
7290
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
 
7291
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
7292
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 
7293
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 
7294
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
7295
+ *
 
7296
+ */
 
7297
+
 
7298
+#include <config.h>
 
7299
+#include <stdio.h>
 
7300
+#include <stdlib.h>
 
7301
+#include <ctype.h>
 
7302
+#include <string.h>
 
7303
+
 
7304
+#include "parseaddr.h"
 
7305
+
 
7306
+#define xmalloc malloc
 
7307
+#define xstrdup strdup
 
7308
+
 
7309
+static char parseaddr_unspecified_domain[] = "unspecified-domain";
 
7310
+
 
7311
+static void parseaddr_append (struct address ***addrpp, char *name,
 
7312
+                               char *route, char *mailbox, char *domain,
 
7313
+                               char **freemep);
 
7314
+static int parseaddr_phrase (char **inp, char **phrasep, char *specials);
 
7315
+static int parseaddr_domain (char **inp, char **domainp, char **commmentp);
 
7316
+static int parseaddr_route (char **inp, char **routep);
 
7317
+
 
7318
+/*
 
7319
+ * Parse an address list in 's', appending address structures to
 
7320
+ * the list pointed to by 'addrp'.
 
7321
+ */
 
7322
+void
 
7323
+parseaddr_list(str, addrp)
 
7324
+const char *str;
 
7325
+struct address **addrp;
 
7326
+{
 
7327
+    char *s;
 
7328
+    int ingroup = 0;
 
7329
+    char *freeme;
 
7330
+    int tok = ' ';
 
7331
+    char *phrase, *route, *mailbox, *domain, *comment;
 
7332
+
 
7333
+    /* Skip down to the tail */
 
7334
+    while (*addrp) {
 
7335
+       addrp = &(*addrp)->next;
 
7336
+    }
 
7337
+
 
7338
+    s = freeme = xstrdup(str);
 
7339
+
 
7340
+    while (tok) {
 
7341
+       tok = parseaddr_phrase(&s, &phrase, ingroup ? ",@<;" : ",@<:");
 
7342
+       switch (tok) {
 
7343
+       case ',':
 
7344
+       case '\0':
 
7345
+       case ';':
 
7346
+           if (*phrase) {
 
7347
+               parseaddr_append(&addrp, 0, 0, phrase, "", &freeme);
 
7348
+           }
 
7349
+           if (tok == ';') {
 
7350
+               parseaddr_append(&addrp, 0, 0, 0, 0, &freeme);
 
7351
+               ingroup = 0;
 
7352
+           }
 
7353
+           continue;
 
7354
+
 
7355
+       case ':':
 
7356
+           parseaddr_append(&addrp, 0, 0, phrase, 0, &freeme);
 
7357
+           ingroup++;
 
7358
+           continue;
 
7359
+
 
7360
+       case '@':
 
7361
+           tok = parseaddr_domain(&s, &domain, &comment);
 
7362
+           parseaddr_append(&addrp, comment, 0, phrase, domain, &freeme);
 
7363
+           continue;
 
7364
+
 
7365
+       case '<':
 
7366
+           tok = parseaddr_phrase(&s, &mailbox, "@>");
 
7367
+           if (tok == '@') {
 
7368
+               route = 0;
 
7369
+               if (!*mailbox) {
 
7370
+                   *--s = '@';
 
7371
+                   tok = parseaddr_route(&s, &route);
 
7372
+                   if (tok != ':') {
 
7373
+                       parseaddr_append(&addrp, phrase, route, "", "", &freeme);
 
7374
+                       while (tok && tok != '>') tok = *s++;
 
7375
+                       continue;
 
7376
+                   }
 
7377
+                   tok = parseaddr_phrase(&s, &mailbox, "@>");
 
7378
+                   if (tok != '@') {
 
7379
+                       parseaddr_append(&addrp, phrase, route, mailbox, "",
 
7380
+                                        &freeme);
 
7381
+                       continue;
 
7382
+                   }
 
7383
+               }
 
7384
+               tok = parseaddr_domain(&s, &domain, 0);
 
7385
+               parseaddr_append(&addrp, phrase, route, mailbox, domain,
 
7386
+                                &freeme);
 
7387
+               while (tok && tok != '>') tok = *s++;
 
7388
+               continue; /* effectively auto-inserts a comma */
 
7389
+           }
 
7390
+           else {
 
7391
+               parseaddr_append(&addrp, phrase, 0, mailbox, "", &freeme);
 
7392
+           }
 
7393
+       }
 
7394
+    }
 
7395
+    if (ingroup) parseaddr_append(&addrp, 0, 0, 0, 0, &freeme);
 
7396
+
 
7397
+    if (freeme) free(freeme);
 
7398
+}
 
7399
+
 
7400
+/*
 
7401
+ * Free the address list 'addr'
 
7402
+ */
 
7403
+void
 
7404
+parseaddr_free(addr)
 
7405
+struct address *addr;
 
7406
+{
 
7407
+    struct address *next;
 
7408
+
 
7409
+    while (addr) {
 
7410
+       if (addr->freeme) free(addr->freeme);
 
7411
+       next = addr->next;
 
7412
+       free((char *)addr);
 
7413
+       addr = next;
 
7414
+    }
 
7415
+}
 
7416
+
 
7417
+/*
 
7418
+ * Helper function to append a new address structure to and address list.
 
7419
+ */
 
7420
+static void
 
7421
+parseaddr_append(addrpp, name, route, mailbox, domain, freemep)
 
7422
+struct address ***addrpp;
 
7423
+char *name;
 
7424
+char *route;
 
7425
+char *mailbox;
 
7426
+char *domain;
 
7427
+char **freemep;
 
7428
+{
 
7429
+    struct address *newaddr;
 
7430
+
 
7431
+    newaddr = (struct address *)xmalloc(sizeof(struct address));
 
7432
+    if (name && *name) {
 
7433
+       newaddr->name = name;
 
7434
+    }
 
7435
+    else {
 
7436
+       newaddr->name = 0;
 
7437
+    }
 
7438
+
 
7439
+    if (route && *route) {
 
7440
+       newaddr->route = route;
 
7441
+    }
 
7442
+    else {
 
7443
+       newaddr->route = 0;
 
7444
+    }
 
7445
+
 
7446
+    newaddr->mailbox = mailbox;
 
7447
+
 
7448
+    if (domain && !*domain) {
 
7449
+       domain = parseaddr_unspecified_domain;
 
7450
+    }
 
7451
+    newaddr->domain = domain;
 
7452
+
 
7453
+    newaddr->next = 0;
 
7454
+    newaddr->freeme = *freemep;
 
7455
+    *freemep = 0;
 
7456
+
 
7457
+    **addrpp = newaddr;
 
7458
+    *addrpp = &newaddr->next;
 
7459
+}
 
7460
+
 
7461
+/* Macro to skip white space and rfc822 comments */
 
7462
+
 
7463
+#define SKIPWHITESPACE(s) \
 
7464
+{ \
 
7465
+    int _c, _comment = 0; \
 
7466
+ \
 
7467
+    while ((_c = *(s))) { \
 
7468
+       if (_c == '(') { \
 
7469
+           _comment = 1; \
 
7470
+           (s)++; \
 
7471
+           while ((_comment && (_c = *(s)))) { \
 
7472
+               (s)++; \
 
7473
+               if (_c == '\\' && *(s)) (s)++; \
 
7474
+               else if (_c == '(') _comment++; \
 
7475
+               else if (_c == ')') _comment--; \
 
7476
+           } \
 
7477
+           (s)--; \
 
7478
+       } \
 
7479
+       else if (!isspace(_c)) break; \
 
7480
+       (s)++; \
 
7481
+    } \
 
7482
+}
 
7483
+
 
7484
+/*
 
7485
+ * Parse an RFC 822 "phrase", stopping at 'specials'
 
7486
+ */
 
7487
+static int parseaddr_phrase(inp, phrasep, specials)
 
7488
+char **inp;
 
7489
+char **phrasep;
 
7490
+char *specials;
 
7491
+{
 
7492
+    int c;
 
7493
+    char *src = *inp;
 
7494
+    char *dst;
 
7495
+
 
7496
+    SKIPWHITESPACE(src);
 
7497
+
 
7498
+    *phrasep = dst = src;
 
7499
+
 
7500
+    for (;;) {
 
7501
+        c = *src++;
 
7502
+       if (c == '\"') {
 
7503
+           while ((c = *src)) {
 
7504
+               src++;
 
7505
+               if (c == '\"') break;
 
7506
+               if (c == '\\') {
 
7507
+                   if (!(c = *src)) break;
 
7508
+                   src++;
 
7509
+               }
 
7510
+               *dst++ = c;
 
7511
+           }
 
7512
+       }
 
7513
+       else if (isspace(c) || c == '(') {
 
7514
+           src--;
 
7515
+           SKIPWHITESPACE(src);
 
7516
+           *dst++ = ' ';
 
7517
+       }
 
7518
+       else if (!c || strchr(specials, c)) {
 
7519
+           if (dst > *phrasep && dst[-1] == ' ') dst--;
 
7520
+           *dst = '\0';
 
7521
+           *inp = src;
 
7522
+           return c;
 
7523
+       }
 
7524
+       else {
 
7525
+           *dst++ = c;
 
7526
+       }
 
7527
+    }
 
7528
+}
 
7529
+
 
7530
+/*
 
7531
+ * Parse a domain.  If 'commentp' is non-nil, parses any trailing comment
 
7532
+ */
 
7533
+static int parseaddr_domain(inp, domainp, commentp)
 
7534
+char **inp;
 
7535
+char **domainp;
 
7536
+char **commentp;
 
7537
+{
 
7538
+    int c;
 
7539
+    char *src = *inp;
 
7540
+    char *dst;
 
7541
+    char *cdst;
 
7542
+    int comment;
 
7543
+
 
7544
+    if (commentp) *commentp = 0;
 
7545
+    SKIPWHITESPACE(src);
 
7546
+
 
7547
+    *domainp = dst = src;
 
7548
+
 
7549
+    for (;;) {
 
7550
+        c = *src++;
 
7551
+       if (isalnum(c) || c == '-' || c == '[' || c == ']' || c == ':') {
 
7552
+           *dst++ = c;
 
7553
+           if (commentp) *commentp = 0;
 
7554
+       }
 
7555
+       else if (c == '.') {
 
7556
+           if (dst > *domainp && dst[-1] != '.') *dst++ = c;
 
7557
+           if (commentp) *commentp = 0;
 
7558
+       }
 
7559
+       else if (c == '(') {
 
7560
+           if (commentp) {
 
7561
+               *commentp = cdst = src;
 
7562
+               comment = 1;
 
7563
+               while (comment && (c = *src)) {
 
7564
+                   src++;
 
7565
+                   if (c == '(') comment++;
 
7566
+                   else if (c == ')') comment--;
 
7567
+                   else if (c == '\\' && (c = *src)) src++;
 
7568
+
 
7569
+                   if (comment) *cdst++ = c;
 
7570
+               }
 
7571
+               *cdst = '\0';
 
7572
+           }
 
7573
+           else {
 
7574
+               src--;
 
7575
+               SKIPWHITESPACE(src);
 
7576
+           }
 
7577
+       }
 
7578
+       else if (!isspace(c)) {
 
7579
+           if (dst > *domainp && dst[-1] == '.') dst--;
 
7580
+           *dst = '\0';
 
7581
+           *inp = src;
 
7582
+           return c;
 
7583
+       }
 
7584
+    }
 
7585
+}
 
7586
+       
 
7587
+/*
 
7588
+ * Parse a source route (at-domain-list)
 
7589
+ */
 
7590
+static int parseaddr_route(inp, routep)
 
7591
+char **inp;
 
7592
+char **routep;
 
7593
+{
 
7594
+    int c;
 
7595
+    char *src = *inp;
 
7596
+    char *dst;
 
7597
+
 
7598
+    SKIPWHITESPACE(src);
 
7599
+
 
7600
+    *routep = dst = src;
 
7601
+
 
7602
+    for (;;) {
 
7603
+        c = *src++;
 
7604
+       if (isalnum(c) || c == '-' || c == '[' || c == ']' ||
 
7605
+           c == ',' || c == '@') {
 
7606
+           *dst++ = c;
 
7607
+       }
 
7608
+       else if (c == '.') {
 
7609
+           if (dst > *routep && dst[-1] != '.') *dst++ = c;
 
7610
+       }
 
7611
+       else if (isspace(c) || c == '(') {
 
7612
+           src--;
 
7613
+           SKIPWHITESPACE(src);
 
7614
+       }
 
7615
+       else {
 
7616
+           while (dst > *routep &&
 
7617
+                  (dst[-1] == '.' || dst[-1] == ',' || dst[-1] == '@')) dst--;
 
7618
+           *dst = '\0';
 
7619
+           *inp = src;
 
7620
+           return c;
 
7621
+       }
 
7622
+    }
 
7623
+}
 
7624
+
 
7625
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/parseaddr.h
 
7626
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
7627
+++ b/src/lib-sieve/cmu/libsieve/parseaddr.h    Sun May 04 16:00:59 2008 +0200
 
7628
@@ -0,0 +1,69 @@
 
7629
+/* parseaddr.h -- RFC 822 address parser
 
7630
+ $Id$
 
7631
 
7632
+ * Copyright (c) 1998-2003 Carnegie Mellon University.  All rights reserved.
 
7633
+ *
 
7634
+ * Redistribution and use in source and binary forms, with or without
 
7635
+ * modification, are permitted provided that the following conditions
 
7636
+ * are met:
 
7637
+ *
 
7638
+ * 1. Redistributions of source code must retain the above copyright
 
7639
+ *    notice, this list of conditions and the following disclaimer. 
 
7640
+ *
 
7641
+ * 2. Redistributions in binary form must reproduce the above copyright
 
7642
+ *    notice, this list of conditions and the following disclaimer in
 
7643
+ *    the documentation and/or other materials provided with the
 
7644
+ *    distribution.
 
7645
+ *
 
7646
+ * 3. The name "Carnegie Mellon University" must not be used to
 
7647
+ *    endorse or promote products derived from this software without
 
7648
+ *    prior written permission. For permission or any other legal
 
7649
+ *    details, please contact  
 
7650
+ *      Office of Technology Transfer
 
7651
+ *      Carnegie Mellon University
 
7652
+ *      5000 Forbes Avenue
 
7653
+ *      Pittsburgh, PA  15213-3890
 
7654
+ *      (412) 268-4387, fax: (412) 268-7395
 
7655
+ *      tech-transfer@andrew.cmu.edu
 
7656
+ *
 
7657
+ * 4. Redistributions of any form whatsoever must retain the following
 
7658
+ *    acknowledgment:
 
7659
+ *    "This product includes software developed by Computing Services
 
7660
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
 
7661
+ *
 
7662
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
7663
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 
7664
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
 
7665
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
7666
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 
7667
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 
7668
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
7669
+ *
 
7670
+ *
 
7671
+ */
 
7672
+
 
7673
+#ifndef INCLUDED_PARSEADDR_H
 
7674
+#define INCLUDED_PARSEADDR_H
 
7675
+
 
7676
+#ifndef P
 
7677
+#ifdef __STDC__
 
7678
+#define P(x) x
 
7679
+#else
 
7680
+#define P(x) ()
 
7681
+#endif
 
7682
+#endif
 
7683
+
 
7684
+struct address {
 
7685
+    char *name;
 
7686
+    char *route;
 
7687
+    char *mailbox;
 
7688
+    char *domain;
 
7689
+    struct address *next;
 
7690
+    char *freeme;              /* If non-nil, free */
 
7691
+};
 
7692
+
 
7693
+extern void parseaddr_list P((const char *s, struct address **addrp));
 
7694
+extern void parseaddr_free P((struct address *addr));
 
7695
+
 
7696
+
 
7697
+#endif /* INCLUDED_PARSEADDR_H */
 
7698
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/script.c
 
7699
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
7700
+++ b/src/lib-sieve/cmu/libsieve/script.c       Sun May 04 16:00:59 2008 +0200
 
7701
@@ -0,0 +1,814 @@
 
7702
+/* script.c -- sieve script functions
 
7703
+ * Larry Greenfield
 
7704
+ * $Id$
 
7705
+ */
 
7706
+/***********************************************************
 
7707
+        Copyright 1999 by Carnegie Mellon University
 
7708
+
 
7709
+                      All Rights Reserved
 
7710
+
 
7711
+Permission to use, copy, modify, and distribute this software and its
 
7712
+documentation for any purpose and without fee is hereby granted,
 
7713
+provided that the above copyright notice appear in all copies and that
 
7714
+both that copyright notice and this permission notice appear in
 
7715
+supporting documentation, and that the name of Carnegie Mellon
 
7716
+University not be used in advertising or publicity pertaining to
 
7717
+distribution of the software without specific, written prior
 
7718
+permission.
 
7719
+
 
7720
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
7721
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
7722
+FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
 
7723
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
7724
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
7725
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 
7726
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
7727
+******************************************************************/
 
7728
+
 
7729
+#ifdef HAVE_CONFIG_H
 
7730
+#include <config.h>
 
7731
+#endif
 
7732
+
 
7733
+#include <stdlib.h>
 
7734
+#include <string.h>
 
7735
+#include <ctype.h>
 
7736
+#include <sys/stat.h>
 
7737
+#include <sys/types.h>
 
7738
+#include <unistd.h>
 
7739
+#include <assert.h>
 
7740
+
 
7741
+#include "xmalloc.h"
 
7742
+
 
7743
+#include "md5.h"
 
7744
+#include "sieve_interface.h"
 
7745
+#include "interp.h"
 
7746
+#include "script.h"
 
7747
+#include "tree.h"
 
7748
+#include "map.h"
 
7749
+#include "sieve.h"
 
7750
+#include "message.h"
 
7751
+#include "bytecode.h"
 
7752
+
 
7753
+/* does this interpretor support this requirement? */
 
7754
+int script_require(sieve_script_t *s, char *req)
 
7755
+{
 
7756
+    if (!strcmp("fileinto", req)) {
 
7757
+       if (s->interp.fileinto) {
 
7758
+           s->support.fileinto = 1;
 
7759
+           return 1;
 
7760
+       } else {
 
7761
+           return 0;
 
7762
+       }
 
7763
+    } else if (!strcmp("reject", req)) {
 
7764
+       if (s->interp.reject) {
 
7765
+           s->support.reject = 1;
 
7766
+           return 1;
 
7767
+       } else {
 
7768
+           return 0;
 
7769
+       }
 
7770
+    } else if (!strcmp("envelope", req)) {
 
7771
+       if (s->interp.getenvelope) {
 
7772
+           s->support.envelope = 1;
 
7773
+           return 1;
 
7774
+       } else {
 
7775
+           return 0;
 
7776
+       }
 
7777
+    } else if (!strcmp("vacation", req)) {
 
7778
+       if (s->interp.vacation) {
 
7779
+           s->support.vacation = 1;
 
7780
+           return 1;
 
7781
+       } else {
 
7782
+           return 0;
 
7783
+       }
 
7784
+    } else if (!strcmp("imapflags", req)) {
 
7785
+       if (s->interp.markflags->flag) {
 
7786
+           s->support.imapflags = 1;
 
7787
+           return 1;
 
7788
+       } else {
 
7789
+           return 0;
 
7790
+       }
 
7791
+    } else if (!strcmp("notify",req)) {
 
7792
+       if (s->interp.notify) {
 
7793
+           s->support.notify = 1;
 
7794
+           return 1;
 
7795
+       } else {
 
7796
+           return 0;
 
7797
+       }
 
7798
+#ifdef ENABLE_REGEX
 
7799
+    } else if (!strcmp("regex", req)) {
 
7800
+       s->support.regex = 1;
 
7801
+       return 1;
 
7802
+#endif
 
7803
+    } else if (!strcmp("subaddress", req)) {
 
7804
+       s->support.subaddress = 1;
 
7805
+       return 1;
 
7806
+    } else if (!strcmp("relational", req)) {
 
7807
+       s->support.relational = 1;
 
7808
+       return 1;
 
7809
+    } else if (!strcmp("comparator-i;octet", req)) {
 
7810
+       return 1;
 
7811
+    } else if (!strcmp("comparator-i;ascii-casemap", req)) {
 
7812
+       return 1;
 
7813
+    } else if (!strcmp("comparator-i;ascii-numeric", req)) {
 
7814
+       s->support.i_ascii_numeric = 1;
 
7815
+       return 1;
 
7816
+    }
 
7817
+    return 0;
 
7818
+}
 
7819
+
 
7820
+/* given an interpretor and a script, produce an executable script */
 
7821
+int sieve_script_parse(sieve_interp_t *interp, FILE *script,
 
7822
+                      void *script_context, sieve_script_t **ret)
 
7823
+{
 
7824
+    sieve_script_t *s;
 
7825
+    int res = SIEVE_OK;
 
7826
+    extern int yylineno;
 
7827
+
 
7828
+    res = interp_verify(interp);
 
7829
+    if (res != SIEVE_OK) {
 
7830
+       return res;
 
7831
+    }
 
7832
+
 
7833
+    s = (sieve_script_t *) xmalloc(sizeof(sieve_script_t));
 
7834
+    s->interp = *interp;
 
7835
+    s->script_context = script_context;
 
7836
+    /* clear all support bits */
 
7837
+    memset(&s->support, 0, sizeof(struct sieve_support));
 
7838
+
 
7839
+    s->err = 0;
 
7840
+
 
7841
+    yylineno = 1;              /* reset line number */
 
7842
+    s->cmds = sieve_parse(s, script);
 
7843
+    if (s->err > 0) {
 
7844
+       if (s->cmds) {
 
7845
+           free_tree(s->cmds);
 
7846
+       }
 
7847
+       s->cmds = NULL;
 
7848
+       res = SIEVE_PARSE_ERROR;
 
7849
+    }
 
7850
+
 
7851
+    *ret = s;
 
7852
+    return res;
 
7853
+}
 
7854
+
 
7855
+static void free_imapflags(sieve_imapflags_t *imapflags)
 
7856
+{
 
7857
+    while (imapflags->nflags)
 
7858
+       free(imapflags->flag[--imapflags->nflags]);
 
7859
+    free(imapflags->flag);
 
7860
+    
 
7861
+    imapflags->flag = NULL;
 
7862
+}
 
7863
+  
 
7864
+int sieve_script_free(sieve_script_t **s)
 
7865
+{
 
7866
+    if (*s) {
 
7867
+       if ((*s)->cmds) {
 
7868
+           free_tree((*s)->cmds);
 
7869
+       }
 
7870
+       free(*s);
 
7871
+    }
 
7872
+
 
7873
+    return SIEVE_OK;
 
7874
+}
 
7875
 
7876
+#define GROW_AMOUNT 100
 
7877
+
 
7878
+static void add_header(sieve_interp_t *i, int isenv, char *header, 
 
7879
+                      void *message_context, char **out, 
 
7880
+                      int *outlen, int *outalloc)
 
7881
+{
 
7882
+    const char **h;
 
7883
+    int addlen;
 
7884
+    /* get header value */
 
7885
+    if (isenv)
 
7886
+       i->getenvelope(message_context, header, &h);    
 
7887
+    else
 
7888
+       i->getheader(message_context, header, &h);      
 
7889
+
 
7890
+    if (!h || !h[0])
 
7891
+       return;
 
7892
+
 
7893
+    addlen = strlen(h[0]) + 1;
 
7894
+
 
7895
+    /* realloc if necessary */
 
7896
+    if ( (*outlen) + addlen >= *outalloc)
 
7897
+    {
 
7898
+       *outalloc = (*outlen) + addlen + GROW_AMOUNT;
 
7899
+       *out = xrealloc(*out, *outalloc);
 
7900
+    }
 
7901
+
 
7902
+    /* add header value */
 
7903
+    strcat(*out,h[0]);
 
7904
+
 
7905
+    *outlen += addlen;
 
7906
+}
 
7907
+
 
7908
+static int fillin_headers(sieve_interp_t *i, const char *msg, 
 
7909
+                         void *message_context, char **out, int *outlen)
 
7910
+{
 
7911
+    int allocsize = GROW_AMOUNT;
 
7912
+    const char *c;
 
7913
+    int n;
 
7914
+
 
7915
+    *out = xmalloc(GROW_AMOUNT);
 
7916
+    *outlen = 0;
 
7917
+    (*out)[0]='\0';
 
7918
+
 
7919
+    if (msg == NULL) return SIEVE_OK;
 
7920
+
 
7921
+    /* construct the message */
 
7922
+    c = msg;
 
7923
+    while (*c) {
 
7924
+       /* expand variables */
 
7925
+       if (!strncasecmp(c, "$from$", 6)) {
 
7926
+           add_header(i, 0 ,"From", message_context, out, outlen, &allocsize);
 
7927
+           c += 6;
 
7928
+       }
 
7929
+       else if (!strncasecmp(c, "$env-from$", 10)) {
 
7930
+           add_header(i, 1, "From", message_context, out, outlen, &allocsize);
 
7931
+           c += 10;
 
7932
+       }
 
7933
+       else if (!strncasecmp(c, "$subject$", 9)) {
 
7934
+           add_header(i, 0, "Subject", message_context, out, outlen, &allocsize);
 
7935
+           c += 9;
 
7936
+       }
 
7937
+       /* XXX need to do $text$ variables */
 
7938
+       else {
 
7939
+           /* find length of plaintext up to next potential variable */
 
7940
+           n = strcspn(c+1, "$") + 1; /* skip opening '$' */
 
7941
+           /* realloc if necessary */
 
7942
+           if ( (*outlen) + n+1 >= allocsize) {
 
7943
+               allocsize = (*outlen) + n+1 + GROW_AMOUNT;
 
7944
+               *out = xrealloc(*out, allocsize);
 
7945
+           }
 
7946
+           /* copy the plaintext */
 
7947
+           strncat(*out, c, n);
 
7948
+           (*out)[*outlen+n]='\0';
 
7949
+           (*outlen) += n;
 
7950
+           c += n;
 
7951
+       }
 
7952
+    }
 
7953
+
 
7954
+    return SIEVE_OK;
 
7955
+}
 
7956
+
 
7957
+static int sieve_addflag(sieve_imapflags_t *imapflags, const char *flag)
 
7958
+{
 
7959
+    int n;
 
7960
+    /* search for flag already in list */
 
7961
+    for (n = 0; n < imapflags->nflags; n++) {
 
7962
+       if (!strcmp(imapflags->flag[n], flag))
 
7963
+           break;
 
7964
+    }
 
7965
 
7966
+    /* add flag to list, iff not in list */
 
7967
+    if (n == imapflags->nflags) {
 
7968
+       imapflags->nflags++;
 
7969
+       imapflags->flag =
 
7970
+           (char **) xrealloc((char *)imapflags->flag,
 
7971
+                              imapflags->nflags*sizeof(char *));
 
7972
+       imapflags->flag[imapflags->nflags-1] = xstrdup(flag);
 
7973
+    }
 
7974
 
7975
+    return SIEVE_OK;
 
7976
+}
 
7977
+
 
7978
+static int sieve_removeflag(sieve_imapflags_t *imapflags, const char *flag)
 
7979
+{
 
7980
+    int n;
 
7981
+    /* search for flag already in list */
 
7982
+    for (n = 0; n < imapflags->nflags; n++) {
 
7983
+      if (!strcmp(imapflags->flag[n], flag))
 
7984
+       break;
 
7985
+    }
 
7986
+    
 
7987
+     /* remove flag from list, iff in list */
 
7988
+    if (n < imapflags->nflags) 
 
7989
+      {
 
7990
+       free(imapflags->flag[n]);
 
7991
+       imapflags->nflags--;
 
7992
+       
 
7993
+       for (; n < imapflags->nflags; n++)
 
7994
+         imapflags->flag[n] = imapflags->flag[n+1];
 
7995
+       
 
7996
+       if (imapflags->nflags)
 
7997
+         {imapflags->flag =
 
7998
+            (char **) xrealloc((char *)imapflags->flag,
 
7999
+                               imapflags->nflags*sizeof(char *));}
 
8000
+       else
 
8001
+         {free(imapflags->flag);
 
8002
+         imapflags->flag=NULL;}
 
8003
+      }
 
8004
+    
 
8005
+    return SIEVE_OK;
 
8006
+}
 
8007
+
 
8008
+static int send_notify_callback(sieve_interp_t *interp, void *message_context, 
 
8009
+                               void * script_context, notify_list_t *notify, 
 
8010
+                               char *actions_string, const char **errmsg)
 
8011
+{
 
8012
+    sieve_notify_context_t nc;
 
8013
+    char *out_msg, *build_msg;
 
8014
+    int out_msglen;    
 
8015
+    int ret;
 
8016
+
 
8017
+    assert(notify->isactive);
 
8018
+
 
8019
+    if (!notify->method || !notify->options ||
 
8020
+       !notify->priority || !notify->message) {
 
8021
+       return SIEVE_RUN_ERROR;
 
8022
+    }
 
8023
+
 
8024
+    nc.method = notify->method;
 
8025
+    nc.options = notify->options ? notify->options : NULL;
 
8026
+    nc.priority = notify->priority;
 
8027
+
 
8028
+    fillin_headers(interp, notify->message, message_context, 
 
8029
+                  &out_msg, &out_msglen);
 
8030
+
 
8031
+    build_msg = xmalloc(out_msglen + strlen(actions_string) + 30);
 
8032
+
 
8033
+    strcpy(build_msg, out_msg);
 
8034
+    strcat(build_msg, "\n\n");
 
8035
+    strcat(build_msg, actions_string);
 
8036
+
 
8037
+    nc.message = build_msg;
 
8038
+
 
8039
+    free(out_msg);
 
8040
+
 
8041
+    ret = interp->notify(&nc,
 
8042
+                        interp->interp_context,
 
8043
+                        script_context,
 
8044
+                        message_context,
 
8045
+                        errmsg);    
 
8046
+
 
8047
+    free(build_msg);
 
8048
+
 
8049
+    return ret;
 
8050
+}
 
8051
+
 
8052
+static char *action_to_string(action_t action)
 
8053
+{
 
8054
+    switch(action)
 
8055
+       {
 
8056
+       case ACTION_REJECT: return "Reject";
 
8057
+       case ACTION_FILEINTO: return "Fileinto";
 
8058
+       case ACTION_KEEP: return "Keep";
 
8059
+       case ACTION_REDIRECT: return "Redirect";
 
8060
+       case ACTION_DISCARD: return "Discard";
 
8061
+       case ACTION_VACATION: return "Vacation";
 
8062
+       case ACTION_SETFLAG: return "Setflag";
 
8063
+       case ACTION_ADDFLAG: return "Addflag";
 
8064
+       case ACTION_REMOVEFLAG: return "Removeflag";
 
8065
+       case ACTION_MARK: return "Mark";
 
8066
+       case ACTION_UNMARK: return "Unmark";
 
8067
+       case ACTION_NOTIFY: return "Notify";
 
8068
+       case ACTION_DENOTIFY: return "Denotify";
 
8069
+       default: return "Unknown";
 
8070
+       }
 
8071
+
 
8072
+    return "Error!";
 
8073
+}
 
8074
+
 
8075
+static char *sieve_errstr(int code)
 
8076
+{
 
8077
+    switch (code)
 
8078
+       {
 
8079
+       case SIEVE_FAIL: return "Generic Error";
 
8080
+       case SIEVE_NOT_FINALIZED: return "Sieve not finalized";
 
8081
+       case SIEVE_PARSE_ERROR: return "Parse error";
 
8082
+       case SIEVE_RUN_ERROR: return "Run error";
 
8083
+       case SIEVE_INTERNAL_ERROR: return "Internal Error";
 
8084
+       case SIEVE_NOMEM: return "No memory";
 
8085
+       default: return "Unknown error";
 
8086
+       }
 
8087
+
 
8088
+    return "Error!";
 
8089
+}
 
8090
+
 
8091
+#define HASHSIZE 16
 
8092
+
 
8093
+static int makehash(unsigned char hash[HASHSIZE],
 
8094
+                   const char *s1, const char *s2)
 
8095
+{
 
8096
+    struct md5_context ctx;
 
8097
+
 
8098
+    md5_init(&ctx);
 
8099
+    md5_update(&ctx, s1, strlen(s1));
 
8100
+    md5_update(&ctx, s2, strlen(s2));
 
8101
+    md5_final(&ctx, hash);
 
8102
+
 
8103
+    return SIEVE_OK;
 
8104
+}
 
8105
+
 
8106
+
 
8107
+/******************************bytecode functions*****************************
 
8108
+ *****************************************************************************/
 
8109
+
 
8110
+/* Load a compiled script */
 
8111
+int sieve_script_load(const char *fname, sieve_bytecode_t **ret) 
 
8112
+{
 
8113
+    struct stat sbuf;
 
8114
+    sieve_bytecode_t *r;
 
8115
+    int fd;
 
8116
+   
 
8117
+    if (!fname || !ret) return SIEVE_FAIL;
 
8118
+    
 
8119
+    fd = open(fname, O_RDONLY);
 
8120
+    if (fd == -1) {
 
8121
+       if (errno != ENOENT)
 
8122
+           i_error("IOERROR: can not open sieve script %s: %m", fname);
 
8123
+       return SIEVE_FAIL;
 
8124
+    }
 
8125
+
 
8126
+    if (fstat(fd, &sbuf) == -1) {
 
8127
+       i_error("IOERROR: fstating sieve script %s: %m", fname);
 
8128
+       close(fd);
 
8129
+       return SIEVE_FAIL;
 
8130
+    }
 
8131
+
 
8132
+    r = (sieve_bytecode_t *) xzmalloc(sizeof(sieve_bytecode_t));
 
8133
+
 
8134
+    r->fd = fd;
 
8135
+    
 
8136
+    map_refresh(fd, 1, &r->data, &r->len, sbuf.st_size, fname, "sievescript");
 
8137
+
 
8138
+    if ((r->len < (BYTECODE_MAGIC_LEN + 2*sizeof(bytecode_input_t))) ||
 
8139
+       memcmp(r->data, BYTECODE_MAGIC, BYTECODE_MAGIC_LEN)) {
 
8140
+       i_error("IOERROR: not a sieve bytecode file %s", fname);
 
8141
+       sieve_script_unload(&r);
 
8142
+       return SIEVE_FAIL;
 
8143
+    }
 
8144
+
 
8145
+    *ret = r;
 
8146
+    return SIEVE_OK;
 
8147
+}
 
8148
+
 
8149
+
 
8150
+
 
8151
+int sieve_script_unload(sieve_bytecode_t **s) 
 
8152
+{
 
8153
+    if(s && *s) {
 
8154
+       map_free(&((*s)->data), &((*s)->len));
 
8155
+       close((*s)->fd);
 
8156
+       free(*s);
 
8157
+       *s = NULL;
 
8158
+    } 
 
8159
+    /*i added this else, i'm not sure why, but this function always returned SIEVE_FAIL*/
 
8160
+    else
 
8161
+      return SIEVE_FAIL;
 
8162
+    return SIEVE_OK;
 
8163
+}
 
8164
+
 
8165
+
 
8166
+#define ACTIONS_STRING_LEN 4096
 
8167
+
 
8168
+static int do_sieve_error(int ret,
 
8169
+                         sieve_interp_t *interp,
 
8170
+                         void *script_context,
 
8171
+                         void *message_context,
 
8172
+                         sieve_imapflags_t * imapflags,
 
8173
+                         action_list_t *actions,
 
8174
+                         notify_list_t *notify_list,
 
8175
+                         /* notify_action_t *notify_action,*/
 
8176
+                         int lastaction,
 
8177
+                         int implicit_keep,
 
8178
+                         char *actions_string,
 
8179
+                         const char *errmsg
 
8180
+                         ) 
 
8181
+{
 
8182
+   if (ret != SIEVE_OK) {
 
8183
+       if (lastaction == -1) /* we never executed an action */
 
8184
+           snprintf(actions_string+strlen(actions_string),
 
8185
+                    ACTIONS_STRING_LEN-strlen(actions_string),
 
8186
+                    "script execution failed: %s\n",
 
8187
+                    errmsg ? errmsg : sieve_errstr(ret));
 
8188
+       else
 
8189
+           snprintf(actions_string+strlen(actions_string),
 
8190
+                    ACTIONS_STRING_LEN-strlen(actions_string),
 
8191
+                    "%s action failed: %s\n",
 
8192
+                    action_to_string(lastaction),
 
8193
+                    errmsg ? errmsg : sieve_errstr(ret));
 
8194
+    }
 
8195
 
8196
+   
 
8197
+    /* Process notify actions */
 
8198
+    if (interp->notify && notify_list) 
 
8199
+      {
 
8200
+       notify_list_t *n = notify_list;
 
8201
+       int notify_ret = SIEVE_OK;
 
8202
+       
 
8203
+       while (n != NULL) 
 
8204
+         {
 
8205
+           if (n->isactive) 
 
8206
+             {
 
8207
+             lastaction = ACTION_NOTIFY;
 
8208
+              notify_ret = send_notify_callback(interp, message_context, 
 
8209
+                                               script_context,n,
 
8210
+                                               actions_string, &errmsg);
 
8211
+             ret |= notify_ret;
 
8212
+             }
 
8213
+           n = n->next;
 
8214
+         }
 
8215
+       
 
8216
+       if (notify_list) free_notify_list(notify_list);
 
8217
+       notify_list = NULL;     /* don't try any notifications again */
 
8218
+       
 
8219
+       
 
8220
+       if (notify_ret != SIEVE_OK) 
 
8221
+         return do_sieve_error(ret, interp, script_context, message_context,
 
8222
+                               imapflags, actions, notify_list, lastaction,
 
8223
+                               implicit_keep, actions_string, errmsg);
 
8224
+      
 
8225
+      }
 
8226
+    
 
8227
+    if ((ret != SIEVE_OK) && interp->err) {
 
8228
+       char buf[1024];
 
8229
+       if (lastaction == -1) /* we never executed an action */
 
8230
+           sprintf(buf, "%s", errmsg ? errmsg : sieve_errstr(ret));
 
8231
+       else
 
8232
+           sprintf(buf, "%s: %s", action_to_string(lastaction),
 
8233
+                   errmsg ? errmsg : sieve_errstr(ret));
 
8234
 
8235
+       ret |= interp->execute_err(buf, interp->interp_context,
 
8236
+                                  script_context, message_context);
 
8237
+    }
 
8238
+
 
8239
+    if (implicit_keep) {
 
8240
+       sieve_keep_context_t keep_context;
 
8241
+       int keep_ret;
 
8242
+       keep_context.imapflags = imapflags;
 
8243
 
8244
+       lastaction = ACTION_KEEP;
 
8245
+       keep_ret = interp->keep(&keep_context, interp->interp_context,
 
8246
+                               script_context, message_context, &errmsg);
 
8247
+       ret |= keep_ret;
 
8248
+        if (keep_ret == SIEVE_OK)
 
8249
+            snprintf(actions_string+strlen(actions_string),
 
8250
+                    sizeof(actions_string)-strlen(actions_string),
 
8251
+                    "Kept\n");
 
8252
+       else {
 
8253
+           implicit_keep = 0;  /* don't try an implicit keep again */
 
8254
+           return do_sieve_error(ret, interp, script_context, message_context,
 
8255
+                                 imapflags, actions, notify_list, lastaction,
 
8256
+                                 implicit_keep, actions_string, errmsg);
 
8257
+       }
 
8258
+    }
 
8259
+
 
8260
+    if (actions)
 
8261
+       free_action_list(actions);
 
8262
+
 
8263
+    return ret;
 
8264
+}
 
8265
+
 
8266
+
 
8267
+static int do_action_list(sieve_interp_t *interp,
 
8268
+                         void *script_context,
 
8269
+                         void *message_context,
 
8270
+                         sieve_imapflags_t *imapflags,
 
8271
+                         action_list_t *actions,
 
8272
+                         notify_list_t *notify_list,
 
8273
+                         /* notify_action_t *notify_action,*/
 
8274
+                         char *actions_string,
 
8275
+                         const char *errmsg) 
 
8276
+{
 
8277
+    action_list_t *a;
 
8278
+    action_t lastaction = -1;
 
8279
+    int ret = 0;
 
8280
+    int implicit_keep = 0;
 
8281
+    
 
8282
+    strcpy(actions_string,"Action(s) taken:\n");
 
8283
+  
 
8284
+    /* now perform actions attached to m */
 
8285
+    a = actions;
 
8286
+    implicit_keep = 1;
 
8287
+    while (a != NULL) {
 
8288
+       lastaction = a->a;
 
8289
+       errmsg = NULL;
 
8290
+       switch (a->a) {
 
8291
+       case ACTION_REJECT:
 
8292
+           implicit_keep = 0;
 
8293
+           if (!interp->reject)
 
8294
+               return SIEVE_INTERNAL_ERROR;
 
8295
+           ret = interp->reject(&a->u.rej,
 
8296
+                                interp->interp_context,
 
8297
+                                script_context,
 
8298
+                                message_context,
 
8299
+                                &errmsg);
 
8300
+           
 
8301
+           if (ret == SIEVE_OK)
 
8302
+               snprintf(actions_string+strlen(actions_string),
 
8303
+                        sizeof(actions_string)-strlen(actions_string), 
 
8304
+                        "Rejected with: %s\n", a->u.rej.msg);
 
8305
+
 
8306
+           break;
 
8307
+       case ACTION_FILEINTO:
 
8308
+           implicit_keep = 0;
 
8309
+           if (!interp->fileinto)
 
8310
+               return SIEVE_INTERNAL_ERROR;
 
8311
+           ret = interp->fileinto(&a->u.fil,
 
8312
+                                  interp->interp_context,
 
8313
+                                  script_context,
 
8314
+                                  message_context,
 
8315
+                                  &errmsg);
 
8316
+
 
8317
+           if (ret == SIEVE_OK)
 
8318
+               snprintf(actions_string+strlen(actions_string),
 
8319
+                        sizeof(actions_string)-strlen(actions_string),
 
8320
+                        "Filed into: %s\n",a->u.fil.mailbox);
 
8321
+           break;
 
8322
+       case ACTION_KEEP:
 
8323
+           implicit_keep = 0;
 
8324
+           if (!interp->keep)
 
8325
+               return SIEVE_INTERNAL_ERROR;
 
8326
+           ret = interp->keep(&a->u.keep,
 
8327
+                              interp->interp_context,
 
8328
+                              script_context,
 
8329
+                              message_context,
 
8330
+                              &errmsg);
 
8331
+           if (ret == SIEVE_OK)
 
8332
+               snprintf(actions_string+strlen(actions_string),
 
8333
+                        sizeof(actions_string)-strlen(actions_string),
 
8334
+                        "Kept\n");
 
8335
+           break;
 
8336
+       case ACTION_REDIRECT:
 
8337
+           implicit_keep = 0;
 
8338
+           if (!interp->redirect)
 
8339
+               return SIEVE_INTERNAL_ERROR;
 
8340
+           ret = interp->redirect(&a->u.red,
 
8341
+                                  interp->interp_context,
 
8342
+                                  script_context,
 
8343
+                                  message_context,
 
8344
+                                  &errmsg);
 
8345
+           if (ret == SIEVE_OK)
 
8346
+               snprintf(actions_string+strlen(actions_string),
 
8347
+                        sizeof(actions_string)-strlen(actions_string),
 
8348
+                        "Redirected to %s\n", a->u.red.addr);
 
8349
+           break;
 
8350
+       case ACTION_DISCARD:
 
8351
+           implicit_keep = 0;
 
8352
+           if (interp->discard) /* discard is optional */
 
8353
+               ret = interp->discard(NULL, interp->interp_context,
 
8354
+                                     script_context,
 
8355
+                                     message_context,
 
8356
+                                     &errmsg);
 
8357
+           if (ret == SIEVE_OK)
 
8358
+               snprintf(actions_string+strlen(actions_string),
 
8359
+                        sizeof(actions_string)-strlen(actions_string),
 
8360
+                        "Discarded\n");
 
8361
+           break;
 
8362
+
 
8363
+       case ACTION_VACATION:
 
8364
+           {
 
8365
+               unsigned char hash[HASHSIZE];
 
8366
+
 
8367
+               if (!interp->vacation)
 
8368
+                   return SIEVE_INTERNAL_ERROR;
 
8369
+
 
8370
+               /* first, let's figure out if we should respond to this */
 
8371
+               ret = makehash(hash, a->u.vac.send.addr,
 
8372
+                              a->u.vac.send.msg);
 
8373
+
 
8374
+               if (ret == SIEVE_OK) {
 
8375
+                   a->u.vac.autoresp.hash = hash;
 
8376
+                   a->u.vac.autoresp.len = HASHSIZE;
 
8377
+                   ret = interp->vacation->autorespond(&a->u.vac.autoresp,
 
8378
+                                                       interp->interp_context,
 
8379
+                                                       script_context,
 
8380
+                                                       message_context,
 
8381
+                                                       &errmsg);
 
8382
+               }
 
8383
+               if (ret == SIEVE_OK) {
 
8384
+                   /* send the response */
 
8385
+                   ret = interp->vacation->send_response(&a->u.vac.send,
 
8386
+                                                         interp->interp_context,
 
8387
+                                                         script_context, 
 
8388
+                                                         message_context,
 
8389
+                                                         &errmsg);
 
8390
+
 
8391
+                   if (ret == SIEVE_OK)
 
8392
+                       snprintf(actions_string+strlen(actions_string),
 
8393
+                                sizeof(actions_string)-strlen(actions_string),
 
8394
+                                "Sent vacation reply\n");
 
8395
+
 
8396
+               } else if (ret == SIEVE_DONE) {
 
8397
+                   snprintf(actions_string+strlen(actions_string),
 
8398
+                            sizeof(actions_string)-strlen(actions_string),
 
8399
+                            "Vacation reply suppressed\n");
 
8400
+
 
8401
+                   ret = SIEVE_OK;
 
8402
+               }
 
8403
+           
 
8404
+               break;
 
8405
+           }
 
8406
+
 
8407
 
8408
+       case ACTION_SETFLAG:
 
8409
+           free_imapflags(imapflags);
 
8410
+           ret = sieve_addflag(imapflags, a->u.fla.flag);
 
8411
+           break;
 
8412
+       case ACTION_ADDFLAG:
 
8413
+           ret = sieve_addflag(imapflags, a->u.fla.flag);
 
8414
+           break;
 
8415
+       case ACTION_REMOVEFLAG:
 
8416
+           ret = sieve_removeflag(imapflags, a->u.fla.flag);
 
8417
+           break;
 
8418
+       case ACTION_MARK:
 
8419
+           {
 
8420
+               int n = interp->markflags->nflags;
 
8421
+
 
8422
+               ret = SIEVE_OK;
 
8423
+               while (n && ret == SIEVE_OK) {
 
8424
+                   ret = sieve_addflag(imapflags,
 
8425
+                                       interp->markflags->flag[--n]);
 
8426
+               }
 
8427
+               break;
 
8428
+           }
 
8429
+       case ACTION_UNMARK:
 
8430
+         {
 
8431
+          
 
8432
+               int n = interp->markflags->nflags;
 
8433
+               ret = SIEVE_OK;
 
8434
+               while (n && ret == SIEVE_OK) {
 
8435
+                   ret = sieve_removeflag(imapflags,
 
8436
+                                          interp->markflags->flag[--n]);
 
8437
+               }
 
8438
+               break;
 
8439
+           }
 
8440
+
 
8441
+       case ACTION_NONE:
 
8442
+           break;
 
8443
+
 
8444
+       default:
 
8445
+           ret = SIEVE_INTERNAL_ERROR;
 
8446
+           break;
 
8447
+       }
 
8448
+       a = a->next;
 
8449
+
 
8450
+       if (ret != SIEVE_OK) {
 
8451
+           /* uh oh! better bail! */
 
8452
+           break;
 
8453
+       }
 
8454
+    }
 
8455
+
 
8456
+    return do_sieve_error(ret, interp, script_context, message_context, 
 
8457
+                         imapflags, actions, notify_list, lastaction, 
 
8458
+                         implicit_keep, actions_string, errmsg);
 
8459
+}
 
8460
+
 
8461
+
 
8462
+int sieve_execute_bytecode(sieve_bytecode_t *bc, sieve_interp_t *interp,
 
8463
+                          void *script_context, void *message_context) 
 
8464
+{
 
8465
+    action_list_t *actions = NULL;
 
8466
+    notify_list_t *notify_list = NULL;
 
8467
+    /*   notify_action_t *notify_action;*/
 
8468
+    action_t lastaction = -1;
 
8469
+    int ret;
 
8470
+    char actions_string[ACTIONS_STRING_LEN] = "";
 
8471
+    const char *errmsg = NULL;
 
8472
+    sieve_imapflags_t imapflags;
 
8473
+    
 
8474
+    if (!interp) return SIEVE_FAIL;
 
8475
+
 
8476
+    imapflags.flag = NULL; 
 
8477
+    imapflags.nflags = 0;
 
8478
+    
 
8479
+    if (interp->notify)
 
8480
+    {
 
8481
+       notify_list = new_notify_list();
 
8482
+       if (notify_list == NULL)
 
8483
+           {
 
8484
+               ret = SIEVE_NOMEM;
 
8485
+               return do_sieve_error(ret, interp, script_context,
 
8486
+                                     message_context, &imapflags,
 
8487
+                                     actions, notify_list, lastaction, 0,
 
8488
+                                     actions_string, errmsg);
 
8489
+           }
 
8490
+    }
 
8491
+
 
8492
+    actions = new_action_list();
 
8493
+    if (actions == NULL) 
 
8494
+    {
 
8495
+       ret = SIEVE_NOMEM;
 
8496
+       return do_sieve_error(ret, interp, script_context,
 
8497
+                             message_context, &imapflags,
 
8498
+                             actions, notify_list, lastaction, 0,
 
8499
+                             actions_string, errmsg);
 
8500
+    }
 
8501
+    
 
8502
+    if (sieve_eval_bc(interp, bc->data, bc->len, message_context, 
 
8503
+                     &imapflags, actions, notify_list, &errmsg) < 0)
 
8504
+    {
 
8505
+       ret = SIEVE_RUN_ERROR;
 
8506
+       return do_sieve_error(ret, interp, script_context,
 
8507
+                             message_context, &imapflags,
 
8508
+                             actions, notify_list, lastaction, 0,
 
8509
+                             actions_string, errmsg);
 
8510
+    }
 
8511
+    
 
8512
+    return do_action_list(interp, script_context, message_context, 
 
8513
+                         &imapflags, actions, notify_list, actions_string,
 
8514
+                         errmsg);
 
8515
+}
 
8516
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/script.h
 
8517
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
8518
+++ b/src/lib-sieve/cmu/libsieve/script.h       Sun May 04 16:00:59 2008 +0200
 
8519
@@ -0,0 +1,74 @@
 
8520
+/* script.h -- script definition
 
8521
+ * Larry Greenfield
 
8522
+ * $Id$
 
8523
+ */
 
8524
+/***********************************************************
 
8525
+        Copyright 1999 by Carnegie Mellon University
 
8526
+
 
8527
+                      All Rights Reserved
 
8528
+
 
8529
+Permission to use, copy, modify, and distribute this software and its
 
8530
+documentation for any purpose and without fee is hereby granted,
 
8531
+provided that the above copyright notice appear in all copies and that
 
8532
+both that copyright notice and this permission notice appear in
 
8533
+supporting documentation, and that the name of Carnegie Mellon
 
8534
+University not be used in advertising or publicity pertaining to
 
8535
+distribution of the software without specific, written prior
 
8536
+permission.
 
8537
+
 
8538
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
8539
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
8540
+FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
 
8541
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
8542
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
8543
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 
8544
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
8545
+******************************************************************/
 
8546
+
 
8547
+#ifndef SIEVE_SCRIPT_H
 
8548
+#define SIEVE_SCRIPT_H
 
8549
+
 
8550
+#include "sieve_interface.h"
 
8551
+#include "interp.h"
 
8552
+#include "tree.h"
 
8553
+
 
8554
+#define ADDRERR_SIZE 500
 
8555
+
 
8556
+struct sieve_script {
 
8557
+    sieve_interp_t interp;
 
8558
+
 
8559
+    /* was a "require" done for these? */
 
8560
+    struct sieve_support {
 
8561
+       int fileinto       : 1;
 
8562
+       int reject         : 1;
 
8563
+       int envelope       : 1;
 
8564
+       int vacation       : 1;
 
8565
+       int imapflags      : 1;
 
8566
+       int notify         : 1;
 
8567
+       int regex          : 1;
 
8568
+       int subaddress     : 1;
 
8569
+       int relational     : 1;
 
8570
+       int i_ascii_numeric: 1;
 
8571
+    } support;
 
8572
+
 
8573
+    void *script_context;
 
8574
+    commandlist_t *cmds;
 
8575
+
 
8576
+    int err;
 
8577
+};
 
8578
+
 
8579
+struct sieve_bytecode
 
8580
+{
 
8581
+    sieve_interp_t *interp;
 
8582
+    void *script_context;
 
8583
+
 
8584
+    const char *data;
 
8585
+    unsigned long len;
 
8586
+    int fd;
 
8587
+};
 
8588
+
 
8589
+/* generated by the yacc script */
 
8590
+commandlist_t *sieve_parse(sieve_script_t *script, FILE *f);
 
8591
+int script_require(sieve_script_t *s, char *req);
 
8592
+
 
8593
+#endif
 
8594
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/sieve-lex.l
 
8595
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
8596
+++ b/src/lib-sieve/cmu/libsieve/sieve-lex.l    Sun May 04 16:00:59 2008 +0200
 
8597
@@ -0,0 +1,162 @@
 
8598
+%{
 
8599
+/* sieve.l -- sieve lexer
 
8600
+ * Larry Greenfield
 
8601
+ * $Id$
 
8602
+ */
 
8603
+/***********************************************************
 
8604
+        Copyright 1999 by Carnegie Mellon University
 
8605
+
 
8606
+                      All Rights Reserved
 
8607
+
 
8608
+Permission to use, copy, modify, and distribute this software and its
 
8609
+documentation for any purpose and without fee is hereby granted,
 
8610
+provided that the above copyright notice appear in all copies and that
 
8611
+both that copyright notice and this permission notice appear in
 
8612
+supporting documentation, and that the name of Carnegie Mellon
 
8613
+University not be used in advertising or publicity pertaining to
 
8614
+distribution of the software without specific, written prior
 
8615
+permission.
 
8616
+
 
8617
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
8618
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
8619
+FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
 
8620
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
8621
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
8622
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 
8623
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
8624
+******************************************************************/
 
8625
+
 
8626
+#ifdef HAVE_CONFIG_H
 
8627
+#include <config.h>
 
8628
+#endif
 
8629
+
 
8630
+#include <string.h> /* for strdup */
 
8631
+#include "xmalloc.h"
 
8632
+
 
8633
+#include "tree.h"
 
8634
+#include "sieve.h"
 
8635
+
 
8636
+#define yylval sievelval
 
8637
+#define yylex sievelex
 
8638
+#define yyerror sieveerror
 
8639
+
 
8640
+static int tonum(char *c);
 
8641
+static char *chkstr(char *);
 
8642
+static char *mlbuf;
 
8643
+static int mlbufsz, mlcur;
 
8644
+extern int yyerror(char *);
 
8645
+%}
 
8646
+
 
8647
+%option yylineno
 
8648
+%option noyywrap
 
8649
+%option nounput
 
8650
+
 
8651
+ws             [ \t]+
 
8652
+ident          [a-zA-Z_][a-zA-Z_0-9]*
 
8653
+CRLF           (\r\n|\r|\n)
 
8654
+
 
8655
+%state MULTILINE
 
8656
+%state QSTRING
 
8657
+
 
8658
+%%
 
8659
+<MULTILINE>^\.{CRLF}   { BEGIN INITIAL; 
 
8660
+                          if (mlbuf) mlbuf[mlcur] = '\0';
 
8661
+                          yylval.sval = chkstr(mlbuf); return STRING; }
 
8662
+<MULTILINE>^\.\.  { /* dot stuffing! we want one . */ yyless(1); }
 
8663
+<MULTILINE>(.|\n) { if (mlcur == mlbufsz) 
 
8664
+                       mlbuf = xrealloc(mlbuf, 1 + (mlbufsz+=1024));
 
8665
+                   mlbuf[mlcur++] = yytext[0]; }
 
8666
+<MULTILINE><<EOF>> { yyerror("unexpected end of file in string"); 
 
8667
+                    yyterminate(); }
 
8668
+<QSTRING>\"        { BEGIN INITIAL;
 
8669
+                     if (mlbuf) mlbuf[mlcur] = '\0';
 
8670
+                    yylval.sval = chkstr(mlbuf); return STRING; }
 
8671
+<QSTRING>\\.      { if (mlcur == mlbufsz) 
 
8672
+                       mlbuf = xrealloc(mlbuf, 1 + (mlbufsz+=1024));
 
8673
+                   mlbuf[mlcur++] = yytext[1]; }
 
8674
+<QSTRING>(.|\n)   { if (mlcur == mlbufsz) 
 
8675
+                       mlbuf = xrealloc(mlbuf, 1 + (mlbufsz+=1024));
 
8676
+                   mlbuf[mlcur++] = yytext[0]; }
 
8677
+<INITIAL>text:{ws}?(#.*)?{CRLF}        { BEGIN MULTILINE;
 
8678
+                         mlcur = 0; mlbufsz = 0; mlbuf = NULL; }
 
8679
+<INITIAL>\"        { BEGIN QSTRING;
 
8680
+                    mlcur = 0; mlbufsz = 0; mlbuf = NULL; }
 
8681
+<INITIAL>[0-9]+[KMG]?  { yylval.nval = tonum(yytext); return NUMBER; }
 
8682
+<INITIAL>if            return IF;
 
8683
+<INITIAL>elsif         return ELSIF;
 
8684
+<INITIAL>else          return ELSE;
 
8685
+<INITIAL>anyof         return ANYOF;
 
8686
+<INITIAL>allof         return ALLOF;
 
8687
+<INITIAL>exists                return EXISTS;
 
8688
+<INITIAL>false         return SFALSE;
 
8689
+<INITIAL>true          return STRUE;
 
8690
+<INITIAL>address       return ADDRESS;
 
8691
+<INITIAL>envelope      return ENVELOPE;
 
8692
+<INITIAL>header                return HEADER;
 
8693
+<INITIAL>not           return NOT;
 
8694
+<INITIAL>size          return SIZE;
 
8695
+<INITIAL>reject                return REJCT;
 
8696
+<INITIAL>fileinto      return FILEINTO;
 
8697
+<INITIAL>redirect      return REDIRECT;
 
8698
+<INITIAL>keep          return KEEP;
 
8699
+<INITIAL>require       return REQUIRE;
 
8700
+<INITIAL>stop          return STOP;
 
8701
+<INITIAL>discard       return DISCARD;
 
8702
+<INITIAL>setflag       return SETFLAG;
 
8703
+<INITIAL>addflag       return ADDFLAG;
 
8704
+<INITIAL>removeflag    return REMOVEFLAG;
 
8705
+<INITIAL>mark          return MARK;
 
8706
+<INITIAL>unmark                return UNMARK;
 
8707
+<INITIAL>notify                return NOTIFY;
 
8708
+<INITIAL>denotify      return DENOTIFY;
 
8709
+<INITIAL>:id           return ID;
 
8710
+<INITIAL>:method       return METHOD;
 
8711
+<INITIAL>:options      return OPTIONS;
 
8712
+<INITIAL>:low          return LOW;
 
8713
+<INITIAL>:normal       return NORMAL;
 
8714
+<INITIAL>:high         return HIGH;
 
8715
+<INITIAL>:message      return MESSAGE;
 
8716
+<INITIAL>vacation      return VACATION;
 
8717
+<INITIAL>:days         return DAYS;
 
8718
+<INITIAL>:addresses    return ADDRESSES;
 
8719
+<INITIAL>:subject      return SUBJECT;
 
8720
+<INITIAL>:mime         return MIME;
 
8721
+<INITIAL>:comparator   return COMPARATOR;
 
8722
+<INITIAL>:is           return IS;
 
8723
+<INITIAL>:contains     return CONTAINS;
 
8724
+<INITIAL>:matches      return MATCHES;
 
8725
+<INITIAL>:regex                return REGEX;
 
8726
+<INITIAL>:count                return COUNT;
 
8727
+<INITIAL>:value                return VALUE;
 
8728
+<INITIAL>:over         return OVER;
 
8729
+<INITIAL>:under                return UNDER;
 
8730
+<INITIAL>:all          return ALL;
 
8731
+<INITIAL>:localpart    return LOCALPART;
 
8732
+<INITIAL>:domain       return DOMAIN;
 
8733
+<INITIAL>:user         return USER;
 
8734
+<INITIAL>:detail       return DETAIL;
 
8735
+<INITIAL>[ \t\n\r] ;   /* ignore whitespace */
 
8736
+<INITIAL>#.* ;         /* ignore hash comments */
 
8737
+<INITIAL>"/*"([^\*]|\*[^\/])*\*?"*/" ; /* ignore bracket comments */
 
8738
+.                      return yytext[0];
 
8739
+
 
8740
+%%
 
8741
+/*  */
 
8742
+static int tonum(char *c)
 
8743
+{
 
8744
+  int val = atoi(c);
 
8745
+  switch (c[strlen(c)-1]) {
 
8746
+  case 'K': val *= (1 << 10); break;
 
8747
+  case 'M': val *= (1 << 20); break;
 
8748
+  case 'G': val *= (1 << 30); break;
 
8749
+  default: break;
 
8750
+  }
 
8751
+  return val;
 
8752
+}
 
8753
+
 
8754
+/* convert NULL strings to "" */
 
8755
+static char *chkstr(char *str)
 
8756
+{
 
8757
+    if (!str) return xstrdup("");
 
8758
+    else return str;
 
8759
+}
 
8760
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/sieve.y
 
8761
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
8762
+++ b/src/lib-sieve/cmu/libsieve/sieve.y        Sun May 04 16:00:59 2008 +0200
 
8763
@@ -0,0 +1,1090 @@
 
8764
+%{
 
8765
+/* sieve.y -- sieve parser
 
8766
+ * Larry Greenfield
 
8767
+ * $Id$
 
8768
+ */
 
8769
+/***********************************************************
 
8770
+        Copyright 1999 by Carnegie Mellon University
 
8771
+
 
8772
+                      All Rights Reserved
 
8773
+
 
8774
+Permission to use, copy, modify, and distribute this software and its
 
8775
+documentation for any purpose and without fee is hereby granted,
 
8776
+provided that the above copyright notice appear in all copies and that
 
8777
+both that copyright notice and this permission notice appear in
 
8778
+supporting documentation, and that the name of Carnegie Mellon
 
8779
+University not be used in advertising or publicity pertaining to
 
8780
+distribution of the software without specific, written prior
 
8781
+permission.
 
8782
+
 
8783
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
8784
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
8785
+FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
 
8786
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
8787
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
8788
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 
8789
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
8790
+******************************************************************/
 
8791
+
 
8792
+#ifdef HAVE_CONFIG_H
 
8793
+#include <config.h>
 
8794
+#endif
 
8795
+
 
8796
+#include <stdlib.h>
 
8797
+#include <assert.h>
 
8798
+#include <string.h>
 
8799
+#include <ctype.h>
 
8800
+#include "xmalloc.h"
 
8801
+#include "comparator.h"
 
8802
+#include "interp.h"
 
8803
+#include "script.h"
 
8804
+#include "tree.h"
 
8805
+
 
8806
+#include "imparse.h"
 
8807
+#include "libconfig.h"
 
8808
+
 
8809
+    /* definitions */
 
8810
+    extern int addrparse(void);
 
8811
+
 
8812
+struct vtags {
 
8813
+    int days;
 
8814
+    stringlist_t *addresses;
 
8815
+    char *subject;
 
8816
+    int mime;
 
8817
+};
 
8818
+
 
8819
+struct htags {
 
8820
+    char *comparator;
 
8821
+    int comptag;
 
8822
+    int relation;
 
8823
+};
 
8824
+
 
8825
+struct aetags {
 
8826
+    int addrtag;
 
8827
+    char *comparator;
 
8828
+    int comptag;
 
8829
+    int relation;
 
8830
+};
 
8831
+
 
8832
+struct ntags {
 
8833
+    char *method;
 
8834
+    char *id;
 
8835
+    stringlist_t *options;
 
8836
+    int priority;
 
8837
+    char *message;
 
8838
+};
 
8839
+
 
8840
+struct dtags {
 
8841
+    int comptag;
 
8842
+    int relation;
 
8843
+    void *pattern;
 
8844
+    int priority;
 
8845
+};
 
8846
+
 
8847
+static commandlist_t *ret;
 
8848
+static sieve_script_t *parse_script;
 
8849
+static int check_reqs(stringlist_t *sl);
 
8850
+static test_t *build_address(int t, struct aetags *ae,
 
8851
+                            stringlist_t *sl, stringlist_t *pl);
 
8852
+static test_t *build_header(int t, struct htags *h,
 
8853
+                           stringlist_t *sl, stringlist_t *pl);
 
8854
+static commandlist_t *build_vacation(int t, struct vtags *h, char *s);
 
8855
+static commandlist_t *build_notify(int t, struct ntags *n);
 
8856
+static commandlist_t *build_denotify(int t, struct dtags *n);
 
8857
+static struct aetags *new_aetags(void);
 
8858
+static struct aetags *canon_aetags(struct aetags *ae);
 
8859
+static void free_aetags(struct aetags *ae);
 
8860
+static struct htags *new_htags(void);
 
8861
+static struct htags *canon_htags(struct htags *h);
 
8862
+static void free_htags(struct htags *h);
 
8863
+static struct vtags *new_vtags(void);
 
8864
+static struct vtags *canon_vtags(struct vtags *v);
 
8865
+static void free_vtags(struct vtags *v);
 
8866
+static struct ntags *new_ntags(void);
 
8867
+static struct ntags *canon_ntags(struct ntags *n);
 
8868
+static void free_ntags(struct ntags *n);
 
8869
+static struct dtags *new_dtags(void);
 
8870
+static struct dtags *canon_dtags(struct dtags *d);
 
8871
+static void free_dtags(struct dtags *d);
 
8872
+
 
8873
+static int verify_stringlist(stringlist_t *sl, int (*verify)(char *));
 
8874
+static int verify_mailbox(char *s);
 
8875
+static int verify_address(char *s);
 
8876
+static int verify_header(char *s);
 
8877
+static int verify_addrheader(char *s);
 
8878
+static int verify_envelope(char *s);
 
8879
+static int verify_flag(char *s);
 
8880
+static int verify_relat(char *s);
 
8881
+#ifdef ENABLE_REGEX
 
8882
+static int verify_regex(char *s, int cflags);
 
8883
+static int verify_regexs(stringlist_t *sl, char *comp);
 
8884
+#endif
 
8885
+static int verify_utf8(char *s);
 
8886
+
 
8887
+int yyerror(char *msg);
 
8888
+extern int yylex(void);
 
8889
+extern void yyrestart(FILE *f);
 
8890
+
 
8891
+#define YYERROR_VERBOSE /* i want better error messages! */
 
8892
+%}
 
8893
+
 
8894
+%union {
 
8895
+    int nval;
 
8896
+    char *sval;
 
8897
+    stringlist_t *sl;
 
8898
+    test_t *test;
 
8899
+    testlist_t *testl;
 
8900
+    commandlist_t *cl;
 
8901
+    struct vtags *vtag;
 
8902
+    struct aetags *aetag;
 
8903
+    struct htags *htag;
 
8904
+    struct ntags *ntag;
 
8905
+    struct dtags *dtag;
 
8906
+}
 
8907
+
 
8908
+%token <nval> NUMBER
 
8909
+%token <sval> STRING
 
8910
+%token IF ELSIF ELSE
 
8911
+%token REJCT FILEINTO REDIRECT KEEP STOP DISCARD VACATION REQUIRE
 
8912
+%token SETFLAG ADDFLAG REMOVEFLAG MARK UNMARK
 
8913
+%token NOTIFY DENOTIFY
 
8914
+%token ANYOF ALLOF EXISTS SFALSE STRUE HEADER NOT SIZE ADDRESS ENVELOPE
 
8915
+%token COMPARATOR IS CONTAINS MATCHES REGEX COUNT VALUE OVER UNDER
 
8916
+%token GT GE LT LE EQ NE
 
8917
+%token ALL LOCALPART DOMAIN USER DETAIL
 
8918
+%token DAYS ADDRESSES SUBJECT MIME
 
8919
+%token METHOD ID OPTIONS LOW NORMAL HIGH ANY MESSAGE
 
8920
+
 
8921
+%type <cl> commands command action elsif block
 
8922
+%type <sl> stringlist strings
 
8923
+%type <test> test
 
8924
+%type <nval> comptag relcomp sizetag addrparttag addrorenv
 
8925
+%type <testl> testlist tests
 
8926
+%type <htag> htags
 
8927
+%type <aetag> aetags
 
8928
+%type <vtag> vtags
 
8929
+%type <ntag> ntags
 
8930
+%type <dtag> dtags
 
8931
+%type <nval> priority
 
8932
+
 
8933
+%%
 
8934
+
 
8935
+start: reqs                    { ret = NULL; }
 
8936
+       | reqs commands         { ret = $2; }
 
8937
+       ;
 
8938
+
 
8939
+reqs: /* empty */
 
8940
+       | require reqs
 
8941
+       ;
 
8942
+
 
8943
+require: REQUIRE stringlist ';'        { if (!check_reqs($2)) {
 
8944
+                                    yyerror("Unsupported features in require line");
 
8945
+                                   YYERROR; 
 
8946
+                                  } }
 
8947
+       ;
 
8948
+
 
8949
+commands: command              { $$ = $1; }
 
8950
+       | command commands      { $1->next = $2; $$ = $1; }
 
8951
+       ;
 
8952
+
 
8953
+command: action ';'            { $$ = $1; }
 
8954
+       | IF test block elsif   { $$ = new_if($2, $3, $4); }
 
8955
+       | error ';'             { $$ = new_command(STOP); }
 
8956
+       ;
 
8957
+
 
8958
+elsif: /* empty */               { $$ = NULL; }
 
8959
+       | ELSIF test block elsif { $$ = new_if($2, $3, $4); }
 
8960
+       | ELSE block             { $$ = $2; }
 
8961
+       ;
 
8962
+
 
8963
+action: REJCT STRING             { if (!parse_script->support.reject) {
 
8964
+                                    yyerror("reject require missing");
 
8965
+                                    YYERROR;
 
8966
+                                  }
 
8967
+                                  if (!verify_utf8($2)) {
 
8968
+                                    YYERROR; /* vu should call yyerror() */
 
8969
+                                  }
 
8970
+                                  $$ = new_command(REJCT);
 
8971
+                                  $$->u.str = $2; }
 
8972
+       | FILEINTO STRING        { if (!parse_script->support.fileinto) {
 
8973
+                                    yyerror("fileinto require missing");
 
8974
+                                    YYERROR;
 
8975
+                                   }
 
8976
+                                  if (!verify_mailbox($2)) {
 
8977
+                                    YYERROR; /* vm should call yyerror() */
 
8978
+                                  }
 
8979
+                                  $$ = new_command(FILEINTO);
 
8980
+                                  $$->u.str = $2; }
 
8981
+       | REDIRECT STRING         { $$ = new_command(REDIRECT);
 
8982
+                                  if (!verify_address($2)) {
 
8983
+                                    YYERROR; /* va should call yyerror() */
 
8984
+                                  }
 
8985
+                                  $$->u.str = $2; }
 
8986
+       | KEEP                   { $$ = new_command(KEEP); }
 
8987
+       | STOP                   { $$ = new_command(STOP); }
 
8988
+       | DISCARD                { $$ = new_command(DISCARD); }
 
8989
+       | VACATION vtags STRING  { if (!parse_script->support.vacation) {
 
8990
+                                    yyerror("vacation require missing");
 
8991
+                                    YYERROR;
 
8992
+                                  }
 
8993
+                                  if (($2->mime == -1) && !verify_utf8($3)) {
 
8994
+                                    YYERROR; /* vu should call yyerror() */
 
8995
+                                  }
 
8996
+                                  $$ = build_vacation(VACATION,
 
8997
+                                           canon_vtags($2), $3); }
 
8998
+        | SETFLAG stringlist     { if (!parse_script->support.imapflags) {
 
8999
+                                    yyerror("imapflags require missing");
 
9000
+                                    YYERROR;
 
9001
+                                   }
 
9002
+                                  if (!verify_stringlist($2, verify_flag)) {
 
9003
+                                    YYERROR; /* vf should call yyerror() */
 
9004
+                                  }
 
9005
+                                  $$ = new_command(SETFLAG);
 
9006
+                                  $$->u.sl = $2; }
 
9007
+         | ADDFLAG stringlist     { if (!parse_script->support.imapflags) {
 
9008
+                                    yyerror("imapflags require missing");
 
9009
+                                    YYERROR;
 
9010
+                                    }
 
9011
+                                  if (!verify_stringlist($2, verify_flag)) {
 
9012
+                                    YYERROR; /* vf should call yyerror() */
 
9013
+                                  }
 
9014
+                                  $$ = new_command(ADDFLAG);
 
9015
+                                  $$->u.sl = $2; }
 
9016
+         | REMOVEFLAG stringlist  { if (!parse_script->support.imapflags) {
 
9017
+                                    yyerror("imapflags require missing");
 
9018
+                                    YYERROR;
 
9019
+                                    }
 
9020
+                                  if (!verify_stringlist($2, verify_flag)) {
 
9021
+                                    YYERROR; /* vf should call yyerror() */
 
9022
+                                  }
 
9023
+                                  $$ = new_command(REMOVEFLAG);
 
9024
+                                  $$->u.sl = $2; }
 
9025
+         | MARK                   { if (!parse_script->support.imapflags) {
 
9026
+                                    yyerror("imapflags require missing");
 
9027
+                                    YYERROR;
 
9028
+                                    }
 
9029
+                                  $$ = new_command(MARK); }
 
9030
+         | UNMARK                 { if (!parse_script->support.imapflags) {
 
9031
+                                    yyerror("imapflags require missing");
 
9032
+                                    YYERROR;
 
9033
+                                    }
 
9034
+                                  $$ = new_command(UNMARK); }
 
9035
+
 
9036
+         | NOTIFY ntags           { if (!parse_script->support.notify) {
 
9037
+                                      yyerror("notify require missing");
 
9038
+                                      $$ = new_command(NOTIFY); 
 
9039
+                                      YYERROR;
 
9040
+                                   } else {
 
9041
+                                     $$ = build_notify(NOTIFY,
 
9042
+                                            canon_ntags($2));
 
9043
+                                   } }
 
9044
+         | DENOTIFY dtags         { if (!parse_script->support.notify) {
 
9045
+                                       yyerror("notify require missing");
 
9046
+                                      $$ = new_command(DENOTIFY);
 
9047
+                                      YYERROR;
 
9048
+                                   } else {
 
9049
+                                       $$ = build_denotify(DENOTIFY, canon_dtags($2));
 
9050
+                                       if ($$ == NULL) { 
 
9051
+                       yyerror("unable to find a compatible comparator");
 
9052
+                       YYERROR; } } }
 
9053
+       ;
 
9054
+
 
9055
+ntags: /* empty */              { $$ = new_ntags(); }
 
9056
+       | ntags ID STRING        { if ($$->id != NULL) { 
 
9057
+                                       yyerror("duplicate :method"); YYERROR; }
 
9058
+                                  else { $$->id = $3; } }
 
9059
+       | ntags METHOD STRING    { if ($$->method != NULL) { 
 
9060
+                                       yyerror("duplicate :method"); YYERROR; }
 
9061
+                                  else { $$->method = $3; } }
 
9062
+       | ntags OPTIONS stringlist { if ($$->options != NULL) { 
 
9063
+                                       yyerror("duplicate :options"); YYERROR; }
 
9064
+                                    else { $$->options = $3; } }
 
9065
+        | ntags priority        { if ($$->priority != -1) { 
 
9066
+                                 yyerror("duplicate :priority"); YYERROR; }
 
9067
+                                   else { $$->priority = $2; } }
 
9068
+       | ntags MESSAGE STRING   { if ($$->message != NULL) { 
 
9069
+                                       yyerror("duplicate :message"); YYERROR; }
 
9070
+                                  else { $$->message = $3; } }
 
9071
+       ;
 
9072
+
 
9073
+dtags: /* empty */              { $$ = new_dtags(); }
 
9074
+       | dtags priority         { if ($$->priority != -1) { 
 
9075
+                               yyerror("duplicate priority level"); YYERROR; }
 
9076
+                                  else { $$->priority = $2; } }
 
9077
+       | dtags comptag STRING   { if ($$->comptag != -1)
 
9078
+                                    { 
 
9079
+                                        yyerror("duplicate comparator type tag"); YYERROR;
 
9080
+                                    }
 
9081
+                                  $$->comptag = $2;
 
9082
+#ifdef ENABLE_REGEX
 
9083
+                                  if ($$->comptag == REGEX)
 
9084
+                                  {
 
9085
+                                      int cflags = REG_EXTENDED |
 
9086
+                                          REG_NOSUB | REG_ICASE;
 
9087
+                                      if (!verify_regex($3, cflags)) { YYERROR; }
 
9088
+                                  }
 
9089
+#endif
 
9090
+                                  $$->pattern = $3;
 
9091
+                                 }
 
9092
+       | dtags relcomp STRING  { $$ = $1;
 
9093
+                                  if ($$->comptag != -1) { 
 
9094
+                       yyerror("duplicate comparator type tag"); YYERROR; }
 
9095
+                                  else { $$->comptag = $2;
 
9096
+                                  $$->relation = verify_relat($3);
 
9097
+                                  if ($$->relation==-1) 
 
9098
+                                    {YYERROR; /*vr called yyerror()*/ }
 
9099
+                                  } }
 
9100
+       ;
 
9101
+
 
9102
+priority: LOW                   { $$ = LOW; }
 
9103
+        | NORMAL                { $$ = NORMAL; }
 
9104
+        | HIGH                  { $$ = HIGH; }
 
9105
+        ;
 
9106
+
 
9107
+vtags: /* empty */              { $$ = new_vtags(); }
 
9108
+       | vtags DAYS NUMBER      { if ($$->days != -1) { 
 
9109
+                                       yyerror("duplicate :days"); YYERROR; }
 
9110
+                                  else { $$->days = $3; } }
 
9111
+       | vtags ADDRESSES stringlist { if ($$->addresses != NULL) { 
 
9112
+                                       yyerror("duplicate :addresses"); 
 
9113
+                                       YYERROR;
 
9114
+                                      } else if (!verify_stringlist($3,
 
9115
+                                                       verify_address)) {
 
9116
+                                         YYERROR;
 
9117
+                                      } else {
 
9118
+                                        $$->addresses = $3; } }
 
9119
+       | vtags SUBJECT STRING   { if ($$->subject != NULL) { 
 
9120
+                                       yyerror("duplicate :subject"); 
 
9121
+                                       YYERROR;
 
9122
+                                  } else if (!verify_utf8($3)) {
 
9123
+                                       YYERROR; /* vu should call yyerror() */
 
9124
+                                  } else { $$->subject = $3; } }
 
9125
+       | vtags MIME             { if ($$->mime != -1) { 
 
9126
+                                       yyerror("duplicate :mime"); 
 
9127
+                                       YYERROR; }
 
9128
+                                  else { $$->mime = MIME; } }
 
9129
+       ;
 
9130
+
 
9131
+stringlist: '[' strings ']'      { $$ = $2; }
 
9132
+       | STRING                 { $$ = new_sl($1, NULL); }
 
9133
+       ;
 
9134
+
 
9135
+strings: STRING                         { $$ = new_sl($1, NULL); }
 
9136
+       | STRING ',' strings     { $$ = new_sl($1, $3); }
 
9137
+       ;
 
9138
+
 
9139
+block: '{' commands '}'                 { $$ = $2; }
 
9140
+       | '{' '}'                { $$ = NULL; }
 
9141
+       ;
 
9142
+
 
9143
+test:     ANYOF testlist        { $$ = new_test(ANYOF); $$->u.tl = $2; }
 
9144
+        | ALLOF testlist        { $$ = new_test(ALLOF); $$->u.tl = $2; }
 
9145
+        | EXISTS stringlist      { $$ = new_test(EXISTS); $$->u.sl = $2; }
 
9146
+        | SFALSE                { $$ = new_test(SFALSE); }
 
9147
+       | STRUE                  { $$ = new_test(STRUE); }
 
9148
+       | HEADER htags stringlist stringlist
 
9149
+                                {
 
9150
+                                    if (!verify_stringlist($3, verify_header)) {
 
9151
+                                        YYERROR; /* vh should call yyerror() */
 
9152
+                                    }
 
9153
+                                    if (!verify_stringlist($4, verify_utf8)) {
 
9154
+                                        YYERROR; /* vu should call yyerror() */
 
9155
+                                    }
 
9156
+                                    
 
9157
+                                    $2 = canon_htags($2);
 
9158
+#ifdef ENABLE_REGEX
 
9159
+                                    if ($2->comptag == REGEX)
 
9160
+                                    {
 
9161
+                                        if (!(verify_regexs($4, $2->comparator)))
 
9162
+                                        { YYERROR; }
 
9163
+                                    }
 
9164
+#endif
 
9165
+                                    $$ = build_header(HEADER, $2, $3, $4);
 
9166
+                                    if ($$ == NULL) { 
 
9167
+                                        yyerror("unable to find a compatible comparator");
 
9168
+                                        YYERROR; } 
 
9169
+                                }
 
9170
+
 
9171
+
 
9172
+        | addrorenv aetags stringlist stringlist
 
9173
+                                { 
 
9174
+                                    if (($1 == ADDRESS) &&
 
9175
+                                        !verify_stringlist($3, verify_addrheader))
 
9176
+                                        { YYERROR; }
 
9177
+                                    else if (($1 == ENVELOPE) &&
 
9178
+                                             !verify_stringlist($3, verify_envelope))
 
9179
+                                        { YYERROR; }
 
9180
+                                    $2 = canon_aetags($2);
 
9181
+#ifdef ENABLE_REGEX
 
9182
+                                    if ($2->comptag == REGEX)
 
9183
+                                    {
 
9184
+                                        if (!( verify_regexs($4, $2->comparator)))
 
9185
+                                        { YYERROR; }
 
9186
+                                    }
 
9187
+#endif
 
9188
+                                    $$ = build_address($1, $2, $3, $4);
 
9189
+                                    if ($$ == NULL) { 
 
9190
+                                        yyerror("unable to find a compatible comparator");
 
9191
+                                        YYERROR; } 
 
9192
+                                }
 
9193
+
 
9194
+       | NOT test               { $$ = new_test(NOT); $$->u.t = $2; }
 
9195
+       | SIZE sizetag NUMBER    { $$ = new_test(SIZE); $$->u.sz.t = $2;
 
9196
+                                  $$->u.sz.n = $3; }
 
9197
+       | error                  { $$ = NULL; }
 
9198
+       ;
 
9199
+
 
9200
+addrorenv: ADDRESS              { $$ = ADDRESS; }
 
9201
+       | ENVELOPE               {if (!parse_script->support.envelope)
 
9202
+                                     {yyerror("envelope require missing"); YYERROR;}
 
9203
+                                 else{$$ = ENVELOPE; }
 
9204
+                                }
 
9205
+
 
9206
+       ;
 
9207
+
 
9208
+aetags: /* empty */              { $$ = new_aetags(); }
 
9209
+        | aetags addrparttag    { $$ = $1;
 
9210
+                                  if ($$->addrtag != -1) { 
 
9211
+                       yyerror("duplicate or conflicting address part tag");
 
9212
+                       YYERROR; }
 
9213
+                                  else { $$->addrtag = $2; } }
 
9214
+       | aetags comptag         { $$ = $1;
 
9215
+                                  if ($$->comptag != -1) { 
 
9216
+                       yyerror("duplicate comparator type tag"); YYERROR; }
 
9217
+                                  else { $$->comptag = $2; } }
 
9218
+       | aetags relcomp STRING{ $$ = $1;
 
9219
+                                  if ($$->comptag != -1) { 
 
9220
+                       yyerror("duplicate comparator type tag"); YYERROR; }
 
9221
+                                  else { $$->comptag = $2;
 
9222
+                                  $$->relation = verify_relat($3);
 
9223
+                                  if ($$->relation==-1) 
 
9224
+                                    {YYERROR; /*vr called yyerror()*/ }
 
9225
+                                  } }
 
9226
+        | aetags COMPARATOR STRING { $$ = $1;
 
9227
+       if ($$->comparator != NULL) { 
 
9228
+                       yyerror("duplicate comparator tag"); YYERROR; }
 
9229
+                                  else if (!strcmp($3, "i;ascii-numeric") &&
 
9230
+                                           !parse_script->support.i_ascii_numeric) {
 
9231
+                       yyerror("comparator-i;ascii-numeric require missing");
 
9232
+                       YYERROR; }
 
9233
+                                  else { $$->comparator = $3; } }
 
9234
+       ;
 
9235
+
 
9236
+htags: /* empty */              { $$ = new_htags(); }
 
9237
+       | htags comptag          { $$ = $1;
 
9238
+                                  if ($$->comptag != -1) { 
 
9239
+                       yyerror("duplicate comparator type tag"); YYERROR; }
 
9240
+                                  else { $$->comptag = $2; } }
 
9241
+       | htags relcomp STRING { $$ = $1;
 
9242
+                                  if ($$->comptag != -1) { 
 
9243
+                       yyerror("duplicate comparator type tag"); YYERROR; }
 
9244
+                                  else { $$->comptag = $2;
 
9245
+                                  $$->relation = verify_relat($3);
 
9246
+                                  if ($$->relation==-1) 
 
9247
+                                    {YYERROR; /*vr called yyerror()*/ }
 
9248
+                                  } }
 
9249
+       | htags COMPARATOR STRING { $$ = $1;
 
9250
+                                  if ($$->comparator != NULL) { 
 
9251
+                        yyerror("duplicate comparator tag"); YYERROR; }
 
9252
+                                  else if (!strcmp($3, "i;ascii-numeric") &&
 
9253
+                                           !parse_script->support.i_ascii_numeric) { 
 
9254
+                        yyerror("comparator-i;ascii-numeric require missing");  YYERROR; }
 
9255
+                                  else { 
 
9256
+                                    $$->comparator = $3; } }
 
9257
+        ;
 
9258
+
 
9259
+
 
9260
+addrparttag: ALL                 { $$ = ALL; }
 
9261
+       | LOCALPART              { $$ = LOCALPART; }
 
9262
+       | DOMAIN                 { $$ = DOMAIN; }
 
9263
+       | USER                   { if (!parse_script->support.subaddress) {
 
9264
+                                    yyerror("subaddress require missing");
 
9265
+                                    YYERROR;
 
9266
+                                  }
 
9267
+                                  $$ = USER; }  
 
9268
+       | DETAIL                { if (!parse_script->support.subaddress) {
 
9269
+                                    yyerror("subaddress require missing");
 
9270
+                                    YYERROR;
 
9271
+                                  }
 
9272
+                                  $$ = DETAIL; }
 
9273
+       ;
 
9274
+comptag: IS                     { $$ = IS; }
 
9275
+       | CONTAINS               { $$ = CONTAINS; }
 
9276
+       | MATCHES                { $$ = MATCHES; }
 
9277
+       | REGEX                  { if (!parse_script->support.regex) {
 
9278
+                                    yyerror("regex require missing");
 
9279
+                                    YYERROR;
 
9280
+                                  }
 
9281
+                                  $$ = REGEX; }
 
9282
+       ;
 
9283
+
 
9284
+relcomp: COUNT                  { if (!parse_script->support.relational) {
 
9285
+                                    yyerror("relational require missing");
 
9286
+                                    YYERROR;
 
9287
+                                  }
 
9288
+                                  $$ = COUNT; }
 
9289
+       | VALUE                  { if (!parse_script->support.relational) {
 
9290
+                                    yyerror("relational require missing");
 
9291
+                                    YYERROR;
 
9292
+                                  }
 
9293
+                                  $$ = VALUE; }
 
9294
+       ;
 
9295
+
 
9296
+
 
9297
+sizetag: OVER                   { $$ = OVER; }
 
9298
+       | UNDER                  { $$ = UNDER; }
 
9299
+       ;
 
9300
+
 
9301
+testlist: '(' tests ')'                 { $$ = $2; }
 
9302
+       ;
 
9303
+
 
9304
+tests: test                      { $$ = new_testlist($1, NULL); }
 
9305
+       | test ',' tests         { $$ = new_testlist($1, $3); }
 
9306
+       ;
 
9307
+
 
9308
+%%
 
9309
+commandlist_t *sieve_parse(sieve_script_t *script, FILE *f)
 
9310
+{
 
9311
+    commandlist_t *t;
 
9312
+
 
9313
+    parse_script = script;
 
9314
+    yyrestart(f);
 
9315
+    if (yyparse()) {
 
9316
+       t = NULL;
 
9317
+    } else {
 
9318
+       t = ret;
 
9319
+    }
 
9320
+    ret = NULL;
 
9321
+    return t;
 
9322
+}
 
9323
+
 
9324
+int yyerror(char *msg)
 
9325
+{
 
9326
+    extern int yylineno;
 
9327
+    int ret;
 
9328
+
 
9329
+    parse_script->err++;
 
9330
+    if (parse_script->interp.err) {
 
9331
+       ret = parse_script->interp.err(yylineno, msg, 
 
9332
+                                      parse_script->interp.interp_context,
 
9333
+                                      parse_script->script_context);
 
9334
+    }
 
9335
+
 
9336
+    return 0;
 
9337
+}
 
9338
+
 
9339
+static int check_reqs(stringlist_t *sl)
 
9340
+{
 
9341
+    int i = 1;
 
9342
+    stringlist_t *s;
 
9343
+    
 
9344
+    while (sl != NULL) {
 
9345
+       s = sl;
 
9346
+       sl = sl->next;
 
9347
+
 
9348
+       i &= script_require(parse_script, s->s);
 
9349
+
 
9350
+       if (s->s) free(s->s);
 
9351
+       free(s);
 
9352
+    }
 
9353
+    return i;
 
9354
+}
 
9355
+
 
9356
+static test_t *build_address(int t, struct aetags *ae,
 
9357
+                            stringlist_t *sl, stringlist_t *pl)
 
9358
+{
 
9359
+    test_t *ret = new_test(t); /* can be either ADDRESS or ENVELOPE */
 
9360
+
 
9361
+    assert((t == ADDRESS) || (t == ENVELOPE));
 
9362
+
 
9363
+    if (ret) {
 
9364
+       ret->u.ae.comptag = ae->comptag;
 
9365
+       ret->u.ae.relation=ae->relation;
 
9366
+       ret->u.ae.comparator=strdup(ae->comparator);
 
9367
+       ret->u.ae.sl = sl;
 
9368
+       ret->u.ae.pl = pl;
 
9369
+       ret->u.ae.addrpart = ae->addrtag;
 
9370
+       free_aetags(ae);
 
9371
+
 
9372
+    }
 
9373
+    return ret;
 
9374
+}
 
9375
+
 
9376
+static test_t *build_header(int t, struct htags *h,
 
9377
+                           stringlist_t *sl, stringlist_t *pl)
 
9378
+{
 
9379
+    test_t *ret = new_test(t); /* can be HEADER */
 
9380
+
 
9381
+    assert(t == HEADER);
 
9382
+
 
9383
+    if (ret) {
 
9384
+       ret->u.h.comptag = h->comptag;
 
9385
+       ret->u.h.relation=h->relation;
 
9386
+       ret->u.h.comparator=strdup(h->comparator);
 
9387
+       ret->u.h.sl = sl;
 
9388
+       ret->u.h.pl = pl;
 
9389
+       free_htags(h);
 
9390
+    }
 
9391
+    return ret;
 
9392
+}
 
9393
+
 
9394
+static commandlist_t *build_vacation(int t, struct vtags *v, char *reason)
 
9395
+{
 
9396
+    commandlist_t *ret = new_command(t);
 
9397
+
 
9398
+    assert(t == VACATION);
 
9399
+
 
9400
+    if (ret) {
 
9401
+       ret->u.v.subject = v->subject; v->subject = NULL;
 
9402
+       ret->u.v.days = v->days;
 
9403
+       ret->u.v.mime = v->mime;
 
9404
+       ret->u.v.addresses = v->addresses; v->addresses = NULL;
 
9405
+       free_vtags(v);
 
9406
+       ret->u.v.message = reason;
 
9407
+    }
 
9408
+    return ret;
 
9409
+}
 
9410
+
 
9411
+static commandlist_t *build_notify(int t, struct ntags *n)
 
9412
+{
 
9413
+    commandlist_t *ret = new_command(t);
 
9414
+
 
9415
+    assert(t == NOTIFY);
 
9416
+       if (ret) {
 
9417
+       ret->u.n.method = n->method; n->method = NULL;
 
9418
+       ret->u.n.id = n->id; n->id = NULL;
 
9419
+       ret->u.n.options = n->options; n->options = NULL;
 
9420
+       ret->u.n.priority = n->priority;
 
9421
+       ret->u.n.message = n->message; n->message = NULL;
 
9422
+       free_ntags(n);
 
9423
+    }
 
9424
+    return ret;
 
9425
+}
 
9426
+
 
9427
+static commandlist_t *build_denotify(int t, struct dtags *d)
 
9428
+{
 
9429
+    commandlist_t *ret = new_command(t);
 
9430
+
 
9431
+    assert(t == DENOTIFY);
 
9432
+
 
9433
+    if (ret) {
 
9434
+       ret->u.d.comptag = d->comptag;
 
9435
+       ret->u.d.relation=d->relation;
 
9436
+       ret->u.d.pattern = d->pattern; d->pattern = NULL;
 
9437
+       ret->u.d.priority = d->priority;
 
9438
+       free_dtags(d);
 
9439
+    }
 
9440
+    return ret;
 
9441
+}
 
9442
+
 
9443
+static struct aetags *new_aetags(void)
 
9444
+{
 
9445
+    struct aetags *r = (struct aetags *) xmalloc(sizeof(struct aetags));
 
9446
+
 
9447
+    r->addrtag = r->comptag = r->relation=-1;
 
9448
+    r->comparator=NULL;
 
9449
+
 
9450
+    return r;
 
9451
+}
 
9452
+
 
9453
+static struct aetags *canon_aetags(struct aetags *ae)
 
9454
+{
 
9455
+    if (ae->addrtag == -1) { ae->addrtag = ALL; }
 
9456
+    if (ae->comparator == NULL) {
 
9457
+        ae->comparator = xstrdup("i;ascii-casemap");
 
9458
+    }
 
9459
+    if (ae->comptag == -1) { ae->comptag = IS; }
 
9460
+    return ae;
 
9461
+}
 
9462
+
 
9463
+static void free_aetags(struct aetags *ae)
 
9464
+{
 
9465
+    free(ae->comparator);
 
9466
+     free(ae);
 
9467
+}
 
9468
+
 
9469
+static struct htags *new_htags(void)
 
9470
+{
 
9471
+    struct htags *r = (struct htags *) xmalloc(sizeof(struct htags));
 
9472
+
 
9473
+    r->comptag = r->relation= -1;
 
9474
+    
 
9475
+    r->comparator = NULL;
 
9476
+
 
9477
+    return r;
 
9478
+}
 
9479
+
 
9480
+static struct htags *canon_htags(struct htags *h)
 
9481
+{
 
9482
+    if (h->comparator == NULL) {
 
9483
+       h->comparator = xstrdup("i;ascii-casemap");
 
9484
+    }
 
9485
+    if (h->comptag == -1) { h->comptag = IS; }
 
9486
+    return h;
 
9487
+}
 
9488
+
 
9489
+static void free_htags(struct htags *h)
 
9490
+{
 
9491
+    free(h->comparator);
 
9492
+    free(h);
 
9493
+}
 
9494
+
 
9495
+static struct vtags *new_vtags(void)
 
9496
+{
 
9497
+    struct vtags *r = (struct vtags *) xmalloc(sizeof(struct vtags));
 
9498
+
 
9499
+    r->days = -1;
 
9500
+    r->addresses = NULL;
 
9501
+    r->subject = NULL;
 
9502
+    r->mime = -1;
 
9503
+
 
9504
+    return r;
 
9505
+}
 
9506
+
 
9507
+static struct vtags *canon_vtags(struct vtags *v)
 
9508
+{
 
9509
+    assert(parse_script->interp.vacation != NULL);
 
9510
+
 
9511
+    if (v->days == -1) { v->days = 7; }
 
9512
+    if (v->days < parse_script->interp.vacation->min_response) 
 
9513
+       { v->days = parse_script->interp.vacation->min_response; }
 
9514
+    if (v->days > parse_script->interp.vacation->max_response)
 
9515
+       { v->days = parse_script->interp.vacation->max_response; }
 
9516
+    if (v->mime == -1) { v->mime = 0; }
 
9517
+
 
9518
+    return v;
 
9519
+}
 
9520
+
 
9521
+static void free_vtags(struct vtags *v)
 
9522
+{
 
9523
+    if (v->addresses) { free_sl(v->addresses); }
 
9524
+    if (v->subject) { free(v->subject); }
 
9525
+    free(v);
 
9526
+}
 
9527
+
 
9528
+static struct ntags *new_ntags(void)
 
9529
+{
 
9530
+    struct ntags *r = (struct ntags *) xmalloc(sizeof(struct ntags));
 
9531
+
 
9532
+    r->method = NULL;
 
9533
+    r->id = NULL;
 
9534
+    r->options = NULL;
 
9535
+    r->priority = -1;
 
9536
+    r->message = NULL;
 
9537
+
 
9538
+    return r;
 
9539
+}
 
9540
+
 
9541
+static struct ntags *canon_ntags(struct ntags *n)
 
9542
+{
 
9543
+    if (n->priority == -1) { n->priority = NORMAL; }
 
9544
+    if (n->message == NULL) { n->message = strdup("$from$: $subject$"); }
 
9545
+    if (n->method == NULL) { n->method = strdup("default"); }
 
9546
+    return n;
 
9547
+}
 
9548
+static struct dtags *canon_dtags(struct dtags *d)
 
9549
+{
 
9550
+    if (d->priority == -1) { d->priority = ANY; }
 
9551
+    if (d->comptag == -1) { d->comptag = ANY; }
 
9552
+       return d;
 
9553
+}
 
9554
+
 
9555
+static void free_ntags(struct ntags *n)
 
9556
+{
 
9557
+    if (n->method) { free(n->method); }
 
9558
+    if (n->id) { free(n->id); }
 
9559
+    if (n->options) { free_sl(n->options); }
 
9560
+    if (n->message) { free(n->message); }
 
9561
+    free(n);
 
9562
+}
 
9563
+
 
9564
+static struct dtags *new_dtags(void)
 
9565
+{
 
9566
+    struct dtags *r = (struct dtags *) xmalloc(sizeof(struct dtags));
 
9567
+
 
9568
+    r->comptag = r->priority= r->relation = -1;
 
9569
+    r->pattern  = NULL;
 
9570
+
 
9571
+    return r;
 
9572
+}
 
9573
+
 
9574
+static void free_dtags(struct dtags *d)
 
9575
+{
 
9576
+    if (d->pattern) free(d->pattern);
 
9577
+    free(d);
 
9578
+}
 
9579
+
 
9580
+static int verify_stringlist(stringlist_t *sl, int (*verify)(char *))
 
9581
+{
 
9582
+    for (; sl != NULL && verify(sl->s); sl = sl->next) ;
 
9583
+    return (sl == NULL);
 
9584
+}
 
9585
+
 
9586
+char *addrptr;         /* pointer to address string for address lexer */
 
9587
+char addrerr[500];     /* buffer for address parser error messages */
 
9588
+
 
9589
+static int verify_address(char *s)
 
9590
+{
 
9591
+    char errbuf[500];
 
9592
+
 
9593
+    addrptr = s;
 
9594
+    addrerr[0] = '\0'; /* paranoia */
 
9595
+    if (addrparse()) {
 
9596
+       snprintf(errbuf, sizeof(errbuf), "address '%s': %s", s, addrerr);
 
9597
+       yyerror(errbuf);
 
9598
+       return 0;
 
9599
+    }
 
9600
+    return 1;
 
9601
+}
 
9602
+
 
9603
+static int verify_mailbox(char *s)
 
9604
+{
 
9605
+    if (!verify_utf8(s)) return 0;
 
9606
+
 
9607
+    /* xxx if not a mailbox, call yyerror */
 
9608
+    return 1;
 
9609
+}
 
9610
+
 
9611
+static int verify_header(char *hdr)
 
9612
+{
 
9613
+    char *h = hdr;
 
9614
+    char errbuf[100];
 
9615
+
 
9616
+    while (*h) {
 
9617
+       /* field-name      =       1*ftext
 
9618
+          ftext           =       %d33-57 / %d59-126         
 
9619
+          ; Any character except
 
9620
+          ;  controls, SP, and
 
9621
+          ;  ":". */
 
9622
+       if (!((*h >= 33 && *h <= 57) || (*h >= 59 && *h <= 126))) {
 
9623
+           snprintf(errbuf, sizeof(errbuf),
 
9624
+                    "header '%s': not a valid header", hdr);
 
9625
+           yyerror(errbuf);
 
9626
+           return 0;
 
9627
+       }
 
9628
+       h++;
 
9629
+    }
 
9630
+    return 1;
 
9631
+}
 
9632
 
9633
+static int verify_addrheader(char *hdr)
 
9634
+{
 
9635
+    const char **h, *hdrs[] = {
 
9636
+       "from", "sender", "reply-to",   /* RFC2822 originator fields */
 
9637
+       "to", "cc", "bcc",              /* RFC2822 destination fields */
 
9638
+       "resent-from", "resent-sender", /* RFC2822 resent fields */
 
9639
+       "resent-to", "resent-cc", "resent-bcc",
 
9640
+       "return-path",                  /* RFC2822 trace fields */
 
9641
+       "disposition-notification-to",  /* RFC2298 MDN request fields */
 
9642
+       "delivered-to",                 /* non-standard (loop detection) */
 
9643
+       "approved",                     /* RFC1036 moderator/control fields */
 
9644
+       NULL
 
9645
+    };
 
9646
+    char errbuf[100];
 
9647
+
 
9648
+    if (!config_getswitch(IMAPOPT_RFC3028_STRICT))
 
9649
+       return verify_header(hdr);
 
9650
+
 
9651
+    for (lcase(hdr), h = hdrs; *h; h++) {
 
9652
+       if (!strcmp(*h, hdr)) return 1;
 
9653
+    }
 
9654
+
 
9655
+    snprintf(errbuf, sizeof(errbuf),
 
9656
+            "header '%s': not a valid header for an address test", hdr);
 
9657
+    yyerror(errbuf);
 
9658
+    return 0;
 
9659
+}
 
9660
 
9661
+static int verify_envelope(char *env)
 
9662
+{
 
9663
+    char errbuf[100];
 
9664
+
 
9665
+    lcase(env);
 
9666
+    if (!config_getswitch(IMAPOPT_RFC3028_STRICT) ||
 
9667
+       !strcmp(env, "from") || !strcmp(env, "to") || !strcmp(env, "auth")) {
 
9668
+       return 1;
 
9669
+    }
 
9670
+
 
9671
+    snprintf(errbuf, sizeof(errbuf),
 
9672
+            "env-part '%s': not a valid part for an envelope test", env);
 
9673
+    yyerror(errbuf);
 
9674
+    return 0;
 
9675
+}
 
9676
 
9677
+static int verify_relat(char *r)
 
9678
+{/* this really should have been a token to begin with.*/
 
9679
+    char errbuf[100];
 
9680
+       lcase(r);
 
9681
+       if (!strcmp(r, "gt")) {return GT;}
 
9682
+       else if (!strcmp(r, "ge")) {return GE;}
 
9683
+       else if (!strcmp(r, "lt")) {return LT;}
 
9684
+       else if (!strcmp(r, "le")) {return LE;}
 
9685
+       else if (!strcmp(r, "ne")) {return NE;}
 
9686
+       else if (!strcmp(r, "eq")) {return EQ;}
 
9687
+       else{
 
9688
+         sprintf(errbuf, "flag '%s': not a valid relational operation", r);
 
9689
+         yyerror(errbuf);
 
9690
+         return -1;
 
9691
+       }
 
9692
+       
 
9693
+}
 
9694
+
 
9695
+
 
9696
+
 
9697
+
 
9698
+static int verify_flag(char *f)
 
9699
+{
 
9700
+    char errbuf[100];
 
9701
 
9702
+    if (f[0] == '\\') {
 
9703
+       lcase(f);
 
9704
+       if (strcmp(f, "\\seen") && strcmp(f, "\\answered") &&
 
9705
+           strcmp(f, "\\flagged") && strcmp(f, "\\draft") &&
 
9706
+           strcmp(f, "\\deleted")) {
 
9707
+           snprintf(errbuf, sizeof(errbuf),
 
9708
+                    "flag '%s': not a system flag", f);
 
9709
+           yyerror(errbuf);
 
9710
+           return 0;
 
9711
+       }
 
9712
+       return 1;
 
9713
+    }
 
9714
+    if (!imparse_isatom(f)) {
 
9715
+       snprintf(errbuf, sizeof(errbuf), "flag '%s': not a valid keyword", f);
 
9716
+       yyerror(errbuf);
 
9717
+       return 0;
 
9718
+    }
 
9719
+    return 1;
 
9720
+}
 
9721
 
9722
+#ifdef ENABLE_REGEX
 
9723
+static int verify_regex(char *s, int cflags)
 
9724
+{
 
9725
+    int ret;
 
9726
+    char errbuf[100];
 
9727
+    regex_t *reg = (regex_t *) xmalloc(sizeof(regex_t));
 
9728
+
 
9729
+     if ((ret = regcomp(reg, s, cflags)) != 0) {
 
9730
+       (void) regerror(ret, reg, errbuf, sizeof(errbuf));
 
9731
+       yyerror(errbuf);
 
9732
+       free(reg);
 
9733
+       return 0;
 
9734
+       }
 
9735
+    free(reg);
 
9736
+    return 1;
 
9737
+}
 
9738
+
 
9739
+static int verify_regexs(stringlist_t *sl, char *comp)
 
9740
+{
 
9741
+    stringlist_t *sl2;
 
9742
+    int cflags = REG_EXTENDED | REG_NOSUB;
 
9743
 
9744
+
 
9745
+    if (!strcmp(comp, "i;ascii-casemap")) {
 
9746
+       cflags |= REG_ICASE;
 
9747
+    }
 
9748
+
 
9749
+    for (sl2 = sl; sl2 != NULL; sl2 = sl2->next) {
 
9750
+       if ((verify_regex(sl2->s, cflags)) == 0) {
 
9751
+           break;
 
9752
+       }
 
9753
+    }
 
9754
+    if (sl2 == NULL) {
 
9755
+       return 1;
 
9756
+    }
 
9757
+    return 0;
 
9758
+}
 
9759
+#endif
 
9760
+
 
9761
+/*
 
9762
+ * Valid UTF-8 check (from RFC 2640 Annex B.1)
 
9763
+ *
 
9764
+ * The following routine checks if a byte sequence is valid UTF-8. This
 
9765
+ * is done by checking for the proper tagging of the first and following
 
9766
+ * bytes to make sure they conform to the UTF-8 format. It then checks
 
9767
+ * to assure that the data part of the UTF-8 sequence conforms to the
 
9768
+ * proper range allowed by the encoding. Note: This routine will not
 
9769
+ * detect characters that have not been assigned and therefore do not
 
9770
+ * exist.
 
9771
+ */
 
9772
+static int verify_utf8(char *s)
 
9773
+{
 
9774
+    const unsigned char *buf = (const unsigned char *)s;
 
9775
+    const unsigned char *endbuf = buf + strlen(s);
 
9776
+    unsigned char byte2mask = 0x00, c;
 
9777
+    int trailing = 0;  /* trailing (continuation) bytes to follow */
 
9778
+
 
9779
+    while (buf != endbuf) {
 
9780
+       c = *buf++;
 
9781
+       if (trailing) {
 
9782
+           if ((c & 0xC0) == 0x80) {           /* Does trailing byte
 
9783
+                                                  follow UTF-8 format? */
 
9784
+               if (byte2mask) {                /* Need to check 2nd byte
 
9785
+                                                  for proper range? */
 
9786
+                   if (c & byte2mask)          /* Are appropriate bits set? */
 
9787
+                       byte2mask = 0x00;
 
9788
+                   else
 
9789
+                       break;
 
9790
+               }
 
9791
+               trailing--;
 
9792
+           }
 
9793
+           else
 
9794
+               break;
 
9795
+       }
 
9796
+       else {
 
9797
+           if ((c & 0x80) == 0x00)             /* valid 1 byte UTF-8 */
 
9798
+               continue;
 
9799
+           else if ((c & 0xE0) == 0xC0)        /* valid 2 byte UTF-8 */
 
9800
+               if (c & 0x1E) {                 /* Is UTF-8 byte
 
9801
+                                                  in proper range? */
 
9802
+                   trailing = 1;
 
9803
+               }
 
9804
+               else
 
9805
+                   break;
 
9806
+           else if ((c & 0xF0) == 0xE0) {      /* valid 3 byte UTF-8 */
 
9807
+               if (!(c & 0x0F)) {              /* Is UTF-8 byte
 
9808
+                                                  in proper range? */
 
9809
+                   byte2mask = 0x20;           /* If not, set mask
 
9810
+                                                  to check next byte */
 
9811
+               }
 
9812
+               trailing = 2;
 
9813
+           }
 
9814
+           else if ((c & 0xF8) == 0xF0) {      /* valid 4 byte UTF-8 */
 
9815
+               if (!(c & 0x07)) {              /* Is UTF-8 byte
 
9816
+                                                  in proper range? */
 
9817
+                   byte2mask = 0x30;           /* If not, set mask
 
9818
+                                                  to check next byte */
 
9819
+               }
 
9820
+               trailing = 3;
 
9821
+           }
 
9822
+           else if ((c & 0xFC) == 0xF8) {      /* valid 5 byte UTF-8 */
 
9823
+               if (!(c & 0x03)) {              /* Is UTF-8 byte
 
9824
+                                                  in proper range? */
 
9825
+                   byte2mask = 0x38;           /* If not, set mask
 
9826
+                                                  to check next byte */
 
9827
+               }
 
9828
+               trailing = 4;
 
9829
+           }
 
9830
+           else if ((c & 0xFE) == 0xFC) {      /* valid 6 byte UTF-8 */
 
9831
+               if (!(c & 0x01)) {              /* Is UTF-8 byte
 
9832
+                                                  in proper range? */
 
9833
+                   byte2mask = 0x3C;           /* If not, set mask
 
9834
+                                                  to check next byte */
 
9835
+               }
 
9836
+               trailing = 5;
 
9837
+           }
 
9838
+           else
 
9839
+               break;
 
9840
+       }
 
9841
+    }
 
9842
+
 
9843
+    if ((buf != endbuf) || trailing) {
 
9844
+       char errbuf[100];
 
9845
+
 
9846
+       snprintf(errbuf, sizeof(errbuf),
 
9847
+                "string '%s': not valid utf8", s);
 
9848
+       yyerror(errbuf);
 
9849
+       return 0;
 
9850
+    }
 
9851
+
 
9852
+    return 1;
 
9853
+}
 
9854
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/sieve_err.c
 
9855
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
9856
+++ b/src/lib-sieve/cmu/libsieve/sieve_err.c    Sun May 04 16:00:59 2008 +0200
 
9857
@@ -0,0 +1,60 @@
 
9858
+/*
 
9859
+ * sieve_err.c:
 
9860
+ * This file is automatically generated; please do not edit it.
 
9861
+ */
 
9862
+
 
9863
+#include <stdlib.h>
 
9864
+
 
9865
+static const char * const text[] = {
 
9866
+          "Generic Sieve error",
 
9867
+          "Sieve interpretor not finalized",
 
9868
+          "Parse error in Sieve script",
 
9869
+          "Run-time error during Sieve execution",
 
9870
+          "Internal error in Sieve subsystem",
 
9871
+          "Memory exhausted in Sieve subsystem",
 
9872
+          "Sieve action already taken",
 
9873
+    0
 
9874
+};
 
9875
+
 
9876
+struct error_table {
 
9877
+    char const * const * msgs;
 
9878
+    long base;
 
9879
+    int n_msgs;
 
9880
+};
 
9881
+struct et_list {
 
9882
+    struct et_list *next;
 
9883
+    const struct error_table * table;
 
9884
+};
 
9885
+extern struct et_list *_et_list;
 
9886
+
 
9887
+const struct error_table et_siev_error_table = { text, -1237848064L, 7 };
 
9888
+
 
9889
+static struct et_list link = { 0, 0 };
 
9890
+
 
9891
+void initialize_siev_error_table(void);
 
9892
+
 
9893
+void initialize_siev_error_table(void) {
 
9894
+    if (!link.table) {
 
9895
+        link.next = _et_list;
 
9896
+        link.table = &et_siev_error_table;
 
9897
+        _et_list = &link;
 
9898
+    }
 
9899
+}
 
9900
+
 
9901
+/* For Heimdal compatibility */
 
9902
+void initialize_siev_error_table_r(struct et_list **list);
 
9903
+
 
9904
+void initialize_siev_error_table_r(struct et_list **list)
 
9905
+{
 
9906
+    struct et_list *et, **end;
 
9907
+
 
9908
+    for (end = list, et = *list; et; end = &et->next, et = et->next)
 
9909
+        if (et->table->msgs == text)
 
9910
+            return;
 
9911
+    et = malloc(sizeof(struct et_list));
 
9912
+    if (et == 0)
 
9913
+        return;
 
9914
+    et->table = &et_siev_error_table;
 
9915
+    et->next = 0;
 
9916
+    *end = et;
 
9917
+}
 
9918
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/sieve_err.h
 
9919
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
9920
+++ b/src/lib-sieve/cmu/libsieve/sieve_err.h    Sun May 04 16:00:59 2008 +0200
 
9921
@@ -0,0 +1,24 @@
 
9922
+/*
 
9923
+ * sieve_err.h:
 
9924
+ * This file used to be automatically generated from sieve_er.et.
 
9925
+ */
 
9926
+struct et_list;
 
9927
+
 
9928
+#define SIEVE_FAIL                               (-1237848064L)
 
9929
+#define SIEVE_NOT_FINALIZED                      (-1237848063L)
 
9930
+#define SIEVE_PARSE_ERROR                        (-1237848062L)
 
9931
+#define SIEVE_RUN_ERROR                          (-1237848061L)
 
9932
+#define SIEVE_INTERNAL_ERROR                     (-1237848060L)
 
9933
+#define SIEVE_NOMEM                              (-1237848059L)
 
9934
+#define SIEVE_DONE                               (-1237848058L)
 
9935
+extern const struct error_table et_siev_error_table;
 
9936
+extern void initialize_siev_error_table(void);
 
9937
+
 
9938
+/* For compatibility with Heimdal */
 
9939
+extern void initialize_siev_error_table_r(struct et_list **list);
 
9940
+
 
9941
+#define ERROR_TABLE_BASE_siev (-1237848064L)
 
9942
+
 
9943
+/* for compatibility with older versions... */
 
9944
+#define init_siev_err_tbl initialize_siev_error_table
 
9945
+#define siev_err_base ERROR_TABLE_BASE_siev
 
9946
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/sieve_interface.h
 
9947
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
9948
+++ b/src/lib-sieve/cmu/libsieve/sieve_interface.h      Sun May 04 16:00:59 2008 +0200
 
9949
@@ -0,0 +1,172 @@
 
9950
+/* sieve_interface.h -- interface for deliver
 
9951
+ * $Id$
 
9952
+ */
 
9953
+/***********************************************************
 
9954
+        Copyright 1999 by Carnegie Mellon University
 
9955
+
 
9956
+                      All Rights Reserved
 
9957
+
 
9958
+Permission to use, copy, modify, and distribute this software and its
 
9959
+documentation for any purpose and without fee is hereby granted,
 
9960
+provided that the above copyright notice appear in all copies and that
 
9961
+both that copyright notice and this permission notice appear in
 
9962
+supporting documentation, and that the name of Carnegie Mellon
 
9963
+University not be used in advertising or publicity pertaining to
 
9964
+distribution of the software without specific, written prior
 
9965
+permission.
 
9966
+
 
9967
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
9968
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
9969
+FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
 
9970
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
9971
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
9972
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 
9973
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
9974
+******************************************************************/
 
9975
+
 
9976
+#ifndef SIEVE_H
 
9977
+#define SIEVE_H
 
9978
+
 
9979
+#include <stdio.h>
 
9980
+
 
9981
+#define SIEVE_VERSION "CMU Sieve 2.2"
 
9982
+
 
9983
+/* error codes */
 
9984
+#define SIEVE_OK (0)
 
9985
+
 
9986
+#include "sieve_err.h"
 
9987
+
 
9988
+/* external sieve types */
 
9989
+typedef struct sieve_interp sieve_interp_t;
 
9990
+typedef struct sieve_script sieve_script_t;
 
9991
+typedef struct sieve_bytecode sieve_bytecode_t;
 
9992
+typedef struct bytecode_info bytecode_info_t;
 
9993
+
 
9994
+typedef int sieve_callback(void *action_context, void *interp_context, 
 
9995
+                          void *script_context,
 
9996
+                          void *message_context, const char **errmsg);
 
9997
+typedef int sieve_get_size(void *message_context, int *size);
 
9998
+typedef int sieve_get_header(void *message_context, 
 
9999
+                            const char *header,
 
10000
+                            const char ***contents);
 
10001
+typedef int sieve_get_envelope(void *message_context, 
 
10002
+                              const char *field,
 
10003
+                              const char ***contents);
 
10004
+
 
10005
+typedef struct sieve_vacation {
 
10006
+    int min_response;          /* 0 -> defaults to 3 */
 
10007
+    int max_response;          /* 0 -> defaults to 90 */
 
10008
+
 
10009
+    /* given a hash, say whether we've already responded to it in the last
 
10010
+       days days.  return SIEVE_OK if we SHOULD autorespond (have not already)
 
10011
+       or SIEVE_DONE if we SHOULD NOT. */
 
10012
+    sieve_callback *autorespond;
 
10013
+
 
10014
+    /* mail the response */
 
10015
+    sieve_callback *send_response;
 
10016
+} sieve_vacation_t;
 
10017
+
 
10018
+typedef struct sieve_imapflags {
 
10019
+    char **flag;               /* NULL -> defaults to \flagged */
 
10020
+    int nflags;
 
10021
+} sieve_imapflags_t;
 
10022
+
 
10023
+typedef struct sieve_redirect_context {
 
10024
+    const char *addr;
 
10025
+} sieve_redirect_context_t;
 
10026
+
 
10027
+typedef struct sieve_reject_context {
 
10028
+    const char *msg;
 
10029
+} sieve_reject_context_t;
 
10030
+
 
10031
+typedef struct sieve_fileinto_context {
 
10032
+    const char *mailbox;
 
10033
+    sieve_imapflags_t *imapflags;
 
10034
+} sieve_fileinto_context_t;
 
10035
+
 
10036
+typedef struct sieve_keep_context {
 
10037
+    sieve_imapflags_t *imapflags;
 
10038
+} sieve_keep_context_t;
 
10039
+
 
10040
+typedef struct sieve_notify_context {
 
10041
+    const char *method;
 
10042
+    const char **options;
 
10043
+    const char *priority;
 
10044
+    const char *message;
 
10045
+} sieve_notify_context_t;
 
10046
+
 
10047
+typedef struct sieve_autorespond_context {
 
10048
+    unsigned char *hash;
 
10049
+    int len;
 
10050
+    int days;
 
10051
+} sieve_autorespond_context_t;
 
10052
+
 
10053
+typedef struct sieve_send_response_context {
 
10054
+    char *addr;
 
10055
+    char *fromaddr;
 
10056
+    const char *msg;
 
10057
+    char *subj;
 
10058
+    int mime;
 
10059
+} sieve_send_response_context_t;
 
10060
+
 
10061
+/* build a sieve interpretor */
 
10062
+int sieve_interp_alloc(sieve_interp_t **interp, void *interp_context);
 
10063
+int sieve_interp_free(sieve_interp_t **interp);
 
10064
+
 
10065
+/* add the callbacks for actions. undefined behavior results if these
 
10066
+   are called after sieve_script_parse is called! */
 
10067
+int sieve_register_redirect(sieve_interp_t *interp, sieve_callback *f);
 
10068
+int sieve_register_discard(sieve_interp_t *interp, sieve_callback *f);
 
10069
+int sieve_register_reject(sieve_interp_t *interp, sieve_callback *f);
 
10070
+int sieve_register_fileinto(sieve_interp_t *interp, sieve_callback *f);
 
10071
+int sieve_register_keep(sieve_interp_t *interp, sieve_callback *f);
 
10072
+int sieve_register_vacation(sieve_interp_t *interp, sieve_vacation_t *v);
 
10073
+int sieve_register_imapflags(sieve_interp_t *interp, sieve_imapflags_t *mark);
 
10074
+int sieve_register_notify(sieve_interp_t *interp, sieve_callback *f);
 
10075
+
 
10076
+/* add the callbacks for messages. again, undefined if used after
 
10077
+   sieve_script_parse */
 
10078
+int sieve_register_size(sieve_interp_t *interp, sieve_get_size *f);
 
10079
+int sieve_register_header(sieve_interp_t *interp, sieve_get_header *f);
 
10080
+int sieve_register_envelope(sieve_interp_t *interp, sieve_get_envelope *f);
 
10081
+
 
10082
+typedef int sieve_parse_error(int lineno, const char *msg, 
 
10083
+                             void *interp_context,
 
10084
+                             void *script_context);
 
10085
+int sieve_register_parse_error(sieve_interp_t *interp, sieve_parse_error *f);
 
10086
+
 
10087
+typedef int sieve_execute_error(const char *msg, void *interp_context,
 
10088
+                               void *script_context, void *message_context);
 
10089
+int sieve_register_execute_error(sieve_interp_t *interp, 
 
10090
+                                sieve_execute_error *f);
 
10091
 
10092
+/* given an interpretor and a script, produce an executable script */
 
10093
+int sieve_script_parse(sieve_interp_t *interp, FILE *script,
 
10094
+                      void *script_context, sieve_script_t **ret);
 
10095
+
 
10096
+/* given a bytecode file descriptor, setup the sieve_bytecode_t */
 
10097
+int sieve_script_load(const char *fname, sieve_bytecode_t **ret);
 
10098
+
 
10099
+/* Unload a sieve_bytecode_t */
 
10100
+int sieve_script_unload(sieve_bytecode_t **s);
 
10101
+
 
10102
+/* Free a sieve_script_t */
 
10103
+int sieve_script_free(sieve_script_t **s);
 
10104
+
 
10105
+/* execute bytecode on a message */
 
10106
+int sieve_execute_bytecode(sieve_bytecode_t *script, sieve_interp_t *interp,
 
10107
+                          void *script_context, void *message_context);
 
10108
+
 
10109
+/* Get space separated list of extensions supported by the implementation */
 
10110
+const char *sieve_listextensions(void);
 
10111
+
 
10112
+/* Create a bytecode structure given a parsed commandlist */
 
10113
+int sieve_generate_bytecode(bytecode_info_t **retval, sieve_script_t *s);
 
10114
+
 
10115
+/* Emit bytecode to a file descriptor */
 
10116
+int sieve_emit_bytecode(int fd, bytecode_info_t *bc);
 
10117
+
 
10118
+/* Free a bytecode_info_t */
 
10119
+void sieve_free_bytecode(bytecode_info_t **p);
 
10120
+
 
10121
+#endif
 
10122
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/sievec.c
 
10123
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
10124
+++ b/src/lib-sieve/cmu/libsieve/sievec.c       Sun May 04 16:00:59 2008 +0200
 
10125
@@ -0,0 +1,273 @@
 
10126
+/* sievec.c -- compile a sieve script to bytecode manually
 
10127
+ * Rob Siemborski
 
10128
+ * $Id$
 
10129
+ */
 
10130
+/*
 
10131
+ * Copyright (c) 1999-2000 Carnegie Mellon University.  All rights reserved.
 
10132
+ *
 
10133
+ * Redistribution and use in source and binary forms, with or without
 
10134
+ * modification, are permitted provided that the following conditions
 
10135
+ * are met:
 
10136
+ *
 
10137
+ * 1. Redistributions of source code must retain the above copyright
 
10138
+ *    notice, this list of conditions and the following disclaimer. 
 
10139
+ *
 
10140
+ * 2. Redistributions in binary form must reproduce the above copyright
 
10141
+ *    notice, this list of conditions and the following disclaimer in
 
10142
+ *    the documentation and/or other materials provided with the
 
10143
+ *    distribution.
 
10144
+ *
 
10145
+ * 3. The name "Carnegie Mellon University" must not be used to
 
10146
+ *    endorse or promote products derived from this software without
 
10147
+ *    prior written permission. For permission or any other legal
 
10148
+ *    details, please contact  
 
10149
+ *      Office of Technology Transfer
 
10150
+ *      Carnegie Mellon University
 
10151
+ *      5000 Forbes Avenue
 
10152
+ *      Pittsburgh, PA  15213-3890
 
10153
+ *      (412) 268-4387, fax: (412) 268-7395
 
10154
+ *      tech-transfer@andrew.cmu.edu
 
10155
+ *
 
10156
+ * 4. Redistributions of any form whatsoever must retain the following
 
10157
+ *    acknowledgment:
 
10158
+ *    "This product includes software developed by Computing Services
 
10159
+ *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
 
10160
+ *
 
10161
+ * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
10162
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 
10163
+ * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
 
10164
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
10165
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
 
10166
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
 
10167
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
10168
+ *
 
10169
+ */
 
10170
+
 
10171
+#ifdef HAVE_CONFIG_H
 
10172
+#include <config.h>
 
10173
+#endif
 
10174
+
 
10175
+#include "sieve_interface.h"
 
10176
+
 
10177
+#include "libconfig.h"
 
10178
+#include "xmalloc.h"
 
10179
+
 
10180
+#include "script.h"
 
10181
+#include <string.h> 
 
10182
+#include <stdlib.h>
 
10183
+#include <sys/file.h>
 
10184
+#include <unistd.h>
 
10185
+#include <stdio.h>
 
10186
+#include <sys/types.h>
 
10187
+#include <sys/stat.h>
 
10188
+#include <fcntl.h>
 
10189
+
 
10190
+struct et_list *_et_list = NULL;
 
10191
+
 
10192
+int is_script_parsable(FILE *stream, char **errstr, sieve_script_t **ret);
 
10193
+
 
10194
+#define TIMSIEVE_FAIL -1
 
10195
+#define TIMSIEVE_OK 0
 
10196
+
 
10197
+int main(int argc, char **argv) 
 
10198
+{
 
10199
+    FILE *instream;
 
10200
+    char *err = NULL;
 
10201
+    sieve_script_t *s;
 
10202
+    bytecode_info_t *bc;
 
10203
+    int c, fd, usage_error = 0;
 
10204
+
 
10205
+    while ((c = getopt(argc, argv, "C:")) != EOF)
 
10206
+       switch (c) {
 
10207
+       default:
 
10208
+           usage_error = 1;
 
10209
+           break;
 
10210
+       }
 
10211
+
 
10212
+    if (usage_error || (argc - optind) < 2) {
 
10213
+       printf("Syntax: %s <filename> <outputfile>\n",
 
10214
+              argv[0]);
 
10215
+       exit(1);
 
10216
+    }
 
10217
+
 
10218
+    instream = fopen(argv[optind++],"r");
 
10219
+    if(instream == NULL) {
 
10220
+       printf("Unable to open %s for reading\n", argv[1]);
 
10221
+       exit(1);
 
10222
+    }
 
10223
+    
 
10224
+    if(is_script_parsable(instream, &err, &s) == TIMSIEVE_FAIL) {
 
10225
+       if(err) {
 
10226
+           printf("Unable to parse script: %s\n", err);
 
10227
+       } else {
 
10228
+           printf("Unable to parse script.\n");
 
10229
+       }
 
10230
+        
 
10231
+       exit(1);
 
10232
+    }
 
10233
+    
 
10234
+    /* Now, generate the bytecode */
 
10235
+    if(sieve_generate_bytecode(&bc, s) == -1) {
 
10236
+       printf("bytecode generate failed\n");
 
10237
+       exit(1);
 
10238
+    }
 
10239
+
 
10240
+    /* Now, open the new file */
 
10241
+    fd = open(argv[optind], O_CREAT | O_TRUNC | O_WRONLY, 0644);
 
10242
+    if(fd < 0) {
 
10243
+       printf("couldn't open bytecode output file\n");
 
10244
+       exit(1);
 
10245
+    }  
 
10246
+
 
10247
+    /* Now, emit the bytecode */
 
10248
+    if(sieve_emit_bytecode(fd, bc) == -1) {
 
10249
+       printf("bytecode emit failed\n");
 
10250
+       exit(1);
 
10251
+    }
 
10252
+
 
10253
+    close(fd);
 
10254
+    
 
10255
+    return 0;
 
10256
+}
 
10257
+
 
10258
+/* to make larry's stupid functions happy :) */ 
 
10259
+static void foo(void)
 
10260
+{
 
10261
+    i_fatal("stub function called");
 
10262
+}
 
10263
+sieve_vacation_t vacation = {
 
10264
+    0,                         /* min response */
 
10265
+    0,                         /* max response */
 
10266
+    (sieve_callback *) &foo,   /* autorespond() */
 
10267
+    (sieve_callback *) &foo    /* send_response() */
 
10268
+};
 
10269
+
 
10270
+static int sieve_notify(void *ac __attr_unused__, 
 
10271
+                       void *interp_context __attr_unused__, 
 
10272
+                       void *script_context __attr_unused__,
 
10273
+                       void *message_context __attr_unused__,
 
10274
+                       const char **errmsg __attr_unused__)
 
10275
+{
 
10276
+    i_fatal("stub function called");
 
10277
+    return SIEVE_FAIL;
 
10278
+}
 
10279
+
 
10280
+static int mysieve_error(int lineno, const char *msg,
 
10281
+                        void *i __attr_unused__, void *s)
 
10282
+{
 
10283
+    char buf[1024];
 
10284
+    char **errstr = (char **) s;
 
10285
+
 
10286
+    snprintf(buf, 80, "line %d: %s\r\n", lineno, msg);
 
10287
+    *errstr = xrealloc(*errstr, strlen(*errstr) + strlen(buf) + 30);
 
10288
+    i_info("%s", buf);
 
10289
+    strcat(*errstr, buf);
 
10290
+
 
10291
+    return SIEVE_OK;
 
10292
+}
 
10293
+
 
10294
+/* end the boilerplate */
 
10295
+
 
10296
+/* returns TRUE or FALSE */
 
10297
+int is_script_parsable(FILE *stream, char **errstr, sieve_script_t **ret)
 
10298
+{
 
10299
+    sieve_interp_t *i;
 
10300
+    sieve_script_t *s;
 
10301
+    int res;
 
10302
+  
 
10303
+    res = sieve_interp_alloc(&i, NULL);
 
10304
+    if (res != SIEVE_OK) {
 
10305
+       i_error("sieve_interp_alloc() returns %d\n", res);
 
10306
+       return TIMSIEVE_FAIL;
 
10307
+    }
 
10308
+
 
10309
+    res = sieve_register_redirect(i, (sieve_callback *) &foo);
 
10310
+    if (res != SIEVE_OK) {
 
10311
+       i_error("sieve_register_redirect() returns %d\n", res);
 
10312
+       return TIMSIEVE_FAIL;
 
10313
+    }
 
10314
+    res = sieve_register_discard(i, (sieve_callback *) &foo);
 
10315
+    if (res != SIEVE_OK) {
 
10316
+       i_error("sieve_register_discard() returns %d\n", res);
 
10317
+       return TIMSIEVE_FAIL;
 
10318
+    }
 
10319
+    res = sieve_register_reject(i, (sieve_callback *) &foo);
 
10320
+    if (res != SIEVE_OK) {
 
10321
+       i_error("sieve_register_reject() returns %d\n", res);
 
10322
+       return TIMSIEVE_FAIL;
 
10323
+    }
 
10324
+    res = sieve_register_fileinto(i, (sieve_callback *) &foo);
 
10325
+    if (res != SIEVE_OK) {
 
10326
+       i_error("sieve_register_fileinto() returns %d\n", res);
 
10327
+       return TIMSIEVE_FAIL;
 
10328
+    }
 
10329
+    res = sieve_register_keep(i, (sieve_callback *) &foo);
 
10330
+    if (res != SIEVE_OK) {
 
10331
+       i_error("sieve_register_keep() returns %d\n", res);
 
10332
+       return TIMSIEVE_FAIL;
 
10333
+    }
 
10334
+
 
10335
+    res = sieve_register_imapflags(i, NULL);
 
10336
+    if (res != SIEVE_OK) {
 
10337
+       i_error("sieve_register_imapflags() returns %d\n", res);
 
10338
+       return TIMSIEVE_FAIL;
 
10339
+    }
 
10340
+
 
10341
+    res = sieve_register_size(i, (sieve_get_size *) &foo);
 
10342
+    if (res != SIEVE_OK) {
 
10343
+       i_error("sieve_register_size() returns %d\n", res);
 
10344
+       return TIMSIEVE_FAIL;
 
10345
+    }
 
10346
+  
 
10347
+    res = sieve_register_header(i, (sieve_get_header *) &foo);
 
10348
+    if (res != SIEVE_OK) {
 
10349
+       i_error("sieve_register_header() returns %d\n", res);
 
10350
+       return TIMSIEVE_FAIL;
 
10351
+    }
 
10352
+  
 
10353
+    res = sieve_register_envelope(i, (sieve_get_envelope *) &foo);
 
10354
+    if (res != SIEVE_OK) {
 
10355
+       i_error("sieve_register_envelope() returns %d\n", res);
 
10356
+       return TIMSIEVE_FAIL;
 
10357
+    }
 
10358
+  
 
10359
+    res = sieve_register_vacation(i, &vacation);
 
10360
+    if (res != SIEVE_OK) {
 
10361
+       i_error("sieve_register_vacation() returns %d\n", res);
 
10362
+       return TIMSIEVE_FAIL;
 
10363
+    }
 
10364
+
 
10365
+    res = sieve_register_notify(i, &sieve_notify);
 
10366
+    if (res != SIEVE_OK) {
 
10367
+       i_error("sieve_register_notify() returns %d\n", res);
 
10368
+       return TIMSIEVE_FAIL;
 
10369
+    }
 
10370
+
 
10371
+    res = sieve_register_parse_error(i, &mysieve_error);
 
10372
+    if (res != SIEVE_OK) {
 
10373
+       i_error("sieve_register_parse_error() returns %d\n", res);
 
10374
+       return TIMSIEVE_FAIL;
 
10375
+    }
 
10376
+
 
10377
+    rewind(stream);
 
10378
+
 
10379
+    *errstr = (char *) xmalloc(20 * sizeof(char));
 
10380
+    strcpy(*errstr, "script errors:\r\n");
 
10381
+
 
10382
+    res = sieve_script_parse(i, stream, errstr, &s);
 
10383
+
 
10384
+    if (res == SIEVE_OK) {
 
10385
+       if(ret) {
 
10386
+           *ret = s;
 
10387
+       } else {
 
10388
+           sieve_script_free(&s);
 
10389
+       }
 
10390
+       free(*errstr);
 
10391
+       *errstr = NULL;
 
10392
+    }
 
10393
+
 
10394
+    /* free interpreter */
 
10395
+    sieve_interp_free(&i);
 
10396
+
 
10397
+    return (res == SIEVE_OK) ? TIMSIEVE_OK : TIMSIEVE_FAIL;
 
10398
+}
 
10399
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/sieved.c
 
10400
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
10401
+++ b/src/lib-sieve/cmu/libsieve/sieved.c       Sun May 04 16:00:59 2008 +0200
 
10402
@@ -0,0 +1,437 @@
 
10403
+/* dump.c -- bytecode decompiler
 
10404
+ * Jen Smith
 
10405
+ */
 
10406
+/***********************************************************
 
10407
+        Copyright 1999 by Carnegie Mellon University
 
10408
+
 
10409
+                      All Rights Reserved
 
10410
+
 
10411
+Permission to use, copy, modify, and distribute this software and its
 
10412
+documentation for any purpose and without fee is hereby granted,
 
10413
+provided that the above copyright notice appear in all copies and that
 
10414
+both that copyright notice and this permission notice appear in
 
10415
+supporting documentation, and that the name of Carnegie Mellon
 
10416
+University not be used in advertising or publicity pertaining to
 
10417
+distribution of the software without specific, written prior
 
10418
+permission.
 
10419
+
 
10420
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
10421
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
10422
+FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
 
10423
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
10424
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
10425
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 
10426
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
10427
+*****************************************************************/
 
10428
+
 
10429
+
 
10430
+
 
10431
+#include "sieve_interface.h"
 
10432
+
 
10433
+#include "bytecode.h"
 
10434
+#include "script.h"
 
10435
+
 
10436
+#include "xmalloc.h"
 
10437
+#include <sys/types.h> 
 
10438
+#include <sys/stat.h>
 
10439
+#include <fcntl.h> 
 
10440
+#include <unistd.h> 
 
10441
+#include <netinet/in.h>
 
10442
+
 
10443
+#include <string.h>
 
10444
+
 
10445
+#include "map.h"
 
10446
+
 
10447
+static void dump2(bytecode_input_t *d, int len);
 
10448
+static int dump2_test(bytecode_input_t * d, int i);
 
10449
+
 
10450
+static int load(int fd, bytecode_input_t ** d)
 
10451
+{  
 
10452
+    const char * data=NULL;
 
10453
+    struct stat sbuf;
 
10454
+    unsigned long len=0;
 
10455
+    
 
10456
+    if (fstat(fd, &sbuf) == -1) {
 
10457
+       printf("IOERROR: fstating sieve script: %m");
 
10458
+       return SIEVE_FAIL;
 
10459
+    }
 
10460
+    
 
10461
+    /*this reads in data and length from file*/
 
10462
+    map_refresh(fd, 1, &(data), &len, sbuf.st_size,
 
10463
+               "sievescript", "");
 
10464
+    *d=(bytecode_input_t *)data;
 
10465
+    
 
10466
+    printf("\n");
 
10467
+    
 
10468
+    return (len/sizeof(int));
 
10469
+}
 
10470
+
 
10471
+
 
10472
+int main(int argc, char * argv[])
 
10473
+{
 
10474
+    bytecode_input_t * bc;
 
10475
+    int script_fd;
 
10476
+    
 
10477
+    unsigned long len;
 
10478
+    
 
10479
+    if (argc!=2) {
 
10480
+        fprintf(stderr, "usage:\n %s script\n", argv[0]);
 
10481
+        exit(1);
 
10482
+    }
 
10483
+
 
10484
+    /*get script*/
 
10485
+    script_fd = open(argv[1], O_RDONLY);
 
10486
+    if (script_fd == -1) 
 
10487
+    {
 
10488
+       printf("can not open script '%s'\n", argv[1]);
 
10489
+       exit(1);
 
10490
+    }
 
10491
+    
 
10492
+    lib_init();
 
10493
+    len=load(script_fd,&bc);
 
10494
+    close(script_fd);
 
10495
+    
 
10496
+    if (bc) {
 
10497
+       dump2(bc, len );
 
10498
+       exit(0);
 
10499
+    } else {
 
10500
+       exit(1);
 
10501
+    }
 
10502
+}
 
10503
+
 
10504
+static int write_list(int list_len, int i, bytecode_input_t * d)
 
10505
+{
 
10506
+    int x;
 
10507
+    i++;
 
10508
+    for (x=0; x<list_len; x++)
 
10509
+    {
 
10510
+       const char *data;
 
10511
+       int len;
 
10512
+       
 
10513
+       i = unwrap_string(d, i, &data, &len);
 
10514
+       
 
10515
+       printf("{%d}%s\n", len, data);
 
10516
+    }
 
10517
+    return i;
 
10518
+}
 
10519
+
 
10520
+static int printComparison(bytecode_input_t *d ,int i)
 
10521
+{
 
10522
+    printf("Comparison: ");
 
10523
+    switch(ntohl(d[i].value))
 
10524
+    {
 
10525
+    case B_IS: printf("Is"); break;
 
10526
+    case B_CONTAINS:printf("Contains"); break;
 
10527
+    case B_MATCHES: printf("Matches"); break;
 
10528
+    case B_REGEX: printf("Regex"); break;
 
10529
+    case B_COUNT:
 
10530
+       printf("Count");
 
10531
+       
 
10532
+       switch(ntohl(d[i+1].value))
 
10533
+       {
 
10534
+       case B_GT: printf(" greater than "); break;   
 
10535
+       case B_GE: printf(" greater than or equal "); break;
 
10536
+       case B_LT: printf(" less than "); break;
 
10537
+       case B_LE: printf(" less than or equal "); break;
 
10538
+       case B_NE: printf(" not equal "); break;
 
10539
+       case B_EQ: printf(" equal "); break;
 
10540
+       }
 
10541
+
 
10542
+       break;
 
10543
+    case B_VALUE:
 
10544
+       printf("Value");
 
10545
+       
 
10546
+       switch(ntohl(d[i+1].value))
 
10547
+       {
 
10548
+       case B_GT: printf(" greater than "); break;   
 
10549
+       case B_GE: printf(" greater than or equal ");break;
 
10550
+       case B_LT: printf(" less than ");    break;
 
10551
+       case B_LE: printf(" less than or equal ");break;
 
10552
+       case B_NE: printf(" not equal ");    break;
 
10553
+       case B_EQ: printf(" equal ");break;
 
10554
+       }
 
10555
+       
 
10556
+       break;
 
10557
+    default:
 
10558
+       exit(1);
 
10559
+    }
 
10560
+
 
10561
+    switch (ntohl(d[i+2].value))
 
10562
+    {
 
10563
+    case B_ASCIICASEMAP: printf("   (ascii-casemap) "); break;
 
10564
+    case B_OCTET: printf("    (octet) "); break;
 
10565
+    case B_ASCIINUMERIC:  printf("   (ascii-numeric) "); break;
 
10566
+    default: exit(1);
 
10567
+    }
 
10568
+    
 
10569
+    printf("\n");
 
10570
+    return i+3;
 
10571
+}
 
10572
+
 
10573
+
 
10574
+static int dump2_test(bytecode_input_t * d, int i)
 
10575
+{
 
10576
+    int l,x;
 
10577
+    switch(ntohl(d[i].value)) {
 
10578
+    case BC_FALSE:
 
10579
+       printf("false");
 
10580
+       i++;
 
10581
+       break;
 
10582
+    case BC_TRUE:
 
10583
+       printf("true");
 
10584
+       i++;
 
10585
+       break;
 
10586
+    case BC_NOT:/*2*/
 
10587
+       /* XXX 
 
10588
+          there is a value being skipped in the second pass...
 
10589
+          no idea what it does, but it isn't carried to here...
 
10590
+          see bytecodee.c */
 
10591
+       printf(" not(");
 
10592
+       i=dump2_test(d, i+1);
 
10593
+       printf(")\n");
 
10594
+       break;
 
10595
+    case BC_EXISTS:
 
10596
+       printf("exists");
 
10597
+       i=write_list(ntohl(d[i+1].len), i+2, d);
 
10598
+       break;
 
10599
+    case BC_SIZE:
 
10600
+       printf("size");
 
10601
+       if (ntohl(d[i+1].value)==B_OVER) {
 
10602
+           /* over */
 
10603
+           printf("over %d", ntohl(d[i+2].value));
 
10604
+       } else {
 
10605
+           /* under */
 
10606
+           printf("under %d", ntohl(d[i+2].value));
 
10607
+       }
 
10608
+       i+=3;
 
10609
+       break;
 
10610
+    case BC_ANYOF:/*5*/
 
10611
+       printf("any of \n(");
 
10612
+       l=ntohl(d[i+1].len);
 
10613
+       i+=3;
 
10614
+       
 
10615
+       for (x=0; x<l; x++)
 
10616
+       {
 
10617
+           i=dump2_test(d,i);
 
10618
+           if((x+1)<l)
 
10619
+               printf(" OR ");
 
10620
+       }
 
10621
+       
 
10622
+       printf(")\n");   
 
10623
+       break;
 
10624
+    case BC_ALLOF:/*6*/
 
10625
+       printf("all of \n(");
 
10626
+       l=ntohl(d[i+1].len);
 
10627
+       i+=3;
 
10628
+       
 
10629
+       for (x=0; x<l; x++)
 
10630
+       {
 
10631
+           i=dump2_test(d,i);
 
10632
+           if((x+1)<l)
 
10633
+               printf(" AND ");
 
10634
+       }
 
10635
+       
 
10636
+       printf(")\n");
 
10637
+       break;
 
10638
+    case BC_ADDRESS:/*7*/
 
10639
+       printf("Address (");
 
10640
+       i=printComparison(d, i+1);
 
10641
+       printf("               type: ");
 
10642
+       switch(ntohl(d[i++].value))
 
10643
+       {
 
10644
+       case B_ALL: printf("all"); break;
 
10645
+       case B_LOCALPART:printf("localpart"); break;
 
10646
+       case B_DOMAIN:printf("domain"); break;
 
10647
+       case B_USER:printf("user"); break;
 
10648
+       case B_DETAIL:printf("detail"); break;
 
10649
+       }
 
10650
+       printf("              Headers:");
 
10651
+       i=write_list(ntohl(d[i].len), i+1, d);
 
10652
+       printf("              Data:");
 
10653
+       i=write_list(ntohl(d[i].len), i+1, d);
 
10654
+       printf("             ]\n");
 
10655
+       break;
 
10656
+    case BC_ENVELOPE:/*8*/
 
10657
+       printf("Envelope (");
 
10658
+       i=printComparison(d, i+1);
 
10659
+       printf("                type: ");
 
10660
+       switch(ntohl(d[i++].value))
 
10661
+       {
 
10662
+       case B_ALL: printf("all"); break;
 
10663
+       case B_LOCALPART:printf("localpart"); break;
 
10664
+       case B_DOMAIN:printf("domain"); break;
 
10665
+       case B_USER:printf("user"); break;
 
10666
+       case B_DETAIL:printf("detail"); break;
 
10667
+       }
 
10668
+       printf("              Headers:");
 
10669
+       i=write_list(ntohl(d[i].len), i+1, d);
 
10670
+       printf("              Data:");
 
10671
+       i=write_list(ntohl(d[i].len), i+1, d);
 
10672
+       printf("             ]\n");
 
10673
+       break;
 
10674
+    case BC_HEADER:/*9*/
 
10675
+       printf("Header [");
 
10676
+       i= printComparison(d, i+1);
 
10677
+       printf("              Headers: ");
 
10678
+       i=write_list(ntohl(d[i].len), i+1, d);
 
10679
+       printf("              Data: ");
 
10680
+       i=write_list(ntohl(d[i].len), i+1, d);
 
10681
+       printf("             ]\n");
 
10682
+       break;
 
10683
+    default:
 
10684
+       printf("WERT %d ", ntohl(d[i].value));
 
10685
+    }   
 
10686
+    return i;
 
10687
+}
 
10688
+
 
10689
+static void dump2(bytecode_input_t *d, int bc_len)
 
10690
+{
 
10691
+    int i;
 
10692
+    const char *data;
 
10693
+    int len;
 
10694
+    
 
10695
+    if(memcmp(d, BYTECODE_MAGIC, BYTECODE_MAGIC_LEN)) {
 
10696
+       printf("not a bytecode file [magic number test failed]\n");
 
10697
+       return;
 
10698
+    }
 
10699
+
 
10700
+    i = BYTECODE_MAGIC_LEN / sizeof(bytecode_input_t);
 
10701
+
 
10702
+    printf("Sievecode version %d\n", ntohl(d[i].op));
 
10703
+    if(!d) return;
 
10704
+    
 
10705
+    for(i++; i<bc_len;) 
 
10706
+    {
 
10707
+       switch(ntohl(d[i].op)) {
 
10708
+           
 
10709
+       case B_STOP:/*0*/
 
10710
+           printf("%d: STOP\n",i);
 
10711
+           i++;
 
10712
+           break;
 
10713
+           
 
10714
+       case B_KEEP:/*1*/
 
10715
+           printf("%d: KEEP\n",i);
 
10716
+           i++;
 
10717
+           break;
 
10718
+           
 
10719
+       case B_DISCARD:/*2*/
 
10720
+           printf("%d: DISCARD\n",i);
 
10721
+           i++;
 
10722
+           break;
 
10723
+           
 
10724
+       case B_REJECT:/*3*/
 
10725
+           i = unwrap_string(d, i+1, &data, &len);
 
10726
+           printf("%d: REJECT {%d}%s\n", i, len, data);
 
10727
+           break;
 
10728
+
 
10729
+       case B_FILEINTO: /*4*/
 
10730
+           i = unwrap_string(d, i+1, &data, &len);
 
10731
+           printf("%d: FILEINTO {%d}%s\n",i, len, data);
 
10732
+           break;
 
10733
+
 
10734
+       case B_REDIRECT: /*5*/
 
10735
+           i = unwrap_string(d, i+1, &data, &len);
 
10736
+           printf("%d: REDIRECT {%d}%s\n",i,len,data);
 
10737
+           break;
 
10738
+            
 
10739
+       case B_IF:/*6*/
 
10740
+           printf("%d: IF (ends at %d)",i, ntohl(d[i+1].value));
 
10741
+
 
10742
+            /* there is no short circuiting involved here*/
 
10743
+           i = dump2_test(d,i+2);
 
10744
+           printf("\n");
 
10745
+
 
10746
+           break;
 
10747
+
 
10748
+       case B_MARK:/*7*/
 
10749
+           printf("%d: MARK\n",i);
 
10750
+           i++;
 
10751
+           break;
 
10752
+
 
10753
+       case B_UNMARK:/*8*/
 
10754
+           printf("%d: UNMARK\n",i);
 
10755
+           i++;
 
10756
+           break;
 
10757
+
 
10758
+       case B_ADDFLAG: /*9*/
 
10759
+           printf("%d: ADDFLAG  {%d}\n",i,ntohl(d[i+1].len));
 
10760
+           i=write_list(ntohl(d[i+1].len),i+2,d);
 
10761
+           break;
 
10762
+
 
10763
+       case B_SETFLAG: /*10*/
 
10764
+           printf("%d: SETFLAG  {%d}\n",i,ntohl(d[i+1].len));
 
10765
+           i=write_list(ntohl(d[i+1].len),i+2,d);
 
10766
+           break;
 
10767
+           
 
10768
+       case B_REMOVEFLAG: /*11*/
 
10769
+           printf("%d: REMOVEFLAG  {%d}\n",i,ntohl(d[i+1].len));
 
10770
+           i=write_list(ntohl(d[i+1].len),i+2,d);
 
10771
+           break;
 
10772
+           
 
10773
+       case B_DENOTIFY:/*12*/
 
10774
+           printf("%d: DENOTIFY\n",i);
 
10775
+           i++; 
 
10776
+           printf("            PRIORITY(%d) Comparison type %d (relat %d)\n",
 
10777
+                  ntohl(d[i].value), ntohl(d[i+1].value), ntohl(d[i+2].value));
 
10778
+           i+=3;
 
10779
+
 
10780
+           i = unwrap_string(d, i+1, &data, &len);
 
10781
+           
 
10782
+           printf("           ({%d}%s)\n", len, (!data ? "[nil]" : data));
 
10783
+           break;
 
10784
+           
 
10785
+       case B_NOTIFY: /*13*/
 
10786
+           i = unwrap_string(d, i+1, &data, &len);
 
10787
+
 
10788
+           printf("%d: NOTIFY METHOD({%d}%s)\n",i,len,data);
 
10789
+
 
10790
+           i = unwrap_string(d, i, &data, &len);
 
10791
+
 
10792
+           printf("            ID({%d}%s) OPTIONS ", len,
 
10793
+                  (!data ? "[nil]" : data));
 
10794
+
 
10795
+           i=write_list(ntohl(d[i].len),i+1,d);
 
10796
+           
 
10797
+           printf("            PRIORITY(%d)\n", ntohl(d[i].value));
 
10798
+           i++;
 
10799
+                 
 
10800
+           i = unwrap_string(d, i, &data, &len);
 
10801
+
 
10802
+           printf("            MESSAGE({%d}%s)\n", len, data);
 
10803
+
 
10804
+           break;
 
10805
+
 
10806
+       case B_VACATION:/*14*/
 
10807
+           printf("%d: VACATION\n",i);
 
10808
+           /*add address list here!*/
 
10809
+           i=write_list(ntohl(d[i+1].len),i+2,d);
 
10810
+
 
10811
+           i = unwrap_string(d, i, &data, &len);
 
10812
+         
 
10813
+           printf("%d SUBJ({%d}%s) \n",i, len, (!data ? "[nil]" : data));
 
10814
+           
 
10815
+           i = unwrap_string(d, i, &data, &len);
 
10816
+
 
10817
+           printf("%d MESG({%d}%s) \n", i, len, (!data ? "[nil]" : data));
 
10818
+
 
10819
+           printf("DAYS(%d) MIME(%d)\n", ntohl(d[i].value), ntohl(d[i+1].value));
 
10820
+           i+=2;
 
10821
+
 
10822
+           break;
 
10823
+       case B_NULL:/*15*/
 
10824
+           printf("%d:NULL\n",i);
 
10825
+           i++;
 
10826
+           break;
 
10827
+       case B_JUMP:/*16*/
 
10828
+           printf("%d:JUMP %d\n",i, ntohl(d[i+1].jump));
 
10829
+           i+=2;
 
10830
+           break;                
 
10831
+       default:
 
10832
+           printf("%d: %d (NOT AN OP)\n",i,ntohl(d[i].op));
 
10833
+           exit(1);
 
10834
+       }
 
10835
+    }
 
10836
+    printf("full len is: %d\n", bc_len);
 
10837
+}
 
10838
+
 
10839
+
 
10840
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/tree.c
 
10841
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
10842
+++ b/src/lib-sieve/cmu/libsieve/tree.c Sun May 04 16:00:59 2008 +0200
 
10843
@@ -0,0 +1,224 @@
 
10844
+/* tree.c -- abstract syntax tree handling
 
10845
+ * Larry Greenfield
 
10846
+ * $Id$
 
10847
+ */
 
10848
+/***********************************************************
 
10849
+        Copyright 1999 by Carnegie Mellon University
 
10850
+
 
10851
+                      All Rights Reserved
 
10852
+
 
10853
+Permission to use, copy, modify, and distribute this software and its
 
10854
+documentation for any purpose and without fee is hereby granted,
 
10855
+provided that the above copyright notice appear in all copies and that
 
10856
+both that copyright notice and this permission notice appear in
 
10857
+supporting documentation, and that the name of Carnegie Mellon
 
10858
+University not be used in advertising or publicity pertaining to
 
10859
+distribution of the software without specific, written prior
 
10860
+permission.
 
10861
+
 
10862
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
10863
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
10864
+FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
 
10865
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
10866
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
10867
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 
10868
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
10869
+******************************************************************/
 
10870
+
 
10871
+#ifdef HAVE_CONFIG_H
 
10872
+#include <config.h>
 
10873
+#endif
 
10874
+
 
10875
+#include <stdlib.h>
 
10876
+#include "xmalloc.h"
 
10877
+
 
10878
+#include "tree.h"
 
10879
+#include "sieve.h"
 
10880
+
 
10881
+stringlist_t *new_sl(char *s, stringlist_t *n)
 
10882
+{
 
10883
+    stringlist_t *p = (stringlist_t *) xmalloc(sizeof(stringlist_t));
 
10884
+    p->s = s;
 
10885
+    p->next = n;
 
10886
+    return p;
 
10887
+}
 
10888
+
 
10889
+
 
10890
+tag_t *new_tag(int type, char *s)
 
10891
+{
 
10892
+    tag_t *p = (tag_t *) xmalloc(sizeof(tag_t));
 
10893
+    p->type = type;
 
10894
+    p->arg = s;
 
10895
+    return p;
 
10896
+}
 
10897
+
 
10898
+taglist_t *new_taglist(tag_t *t, taglist_t *n)
 
10899
+{
 
10900
+    taglist_t *p = (taglist_t *) xmalloc(sizeof(taglist_t));
 
10901
+    p->t = t;
 
10902
+    p->next = n;
 
10903
+    return p;
 
10904
+}
 
10905
+
 
10906
+test_t *new_test(int type) 
 
10907
+{
 
10908
+    test_t *p = (test_t *) xmalloc(sizeof(test_t));
 
10909
+    p->type = type;
 
10910
+    return p;
 
10911
+}
 
10912
+
 
10913
+testlist_t *new_testlist(test_t *t, testlist_t *n)
 
10914
+{
 
10915
+    testlist_t *p = (testlist_t *) xmalloc(sizeof(testlist_t));
 
10916
+    p->t = t;
 
10917
+    p->next = n;
 
10918
+    return p;
 
10919
+}
 
10920
+
 
10921
+commandlist_t *new_command(int type)
 
10922
+{
 
10923
+    commandlist_t *p = (commandlist_t *) xmalloc(sizeof(commandlist_t));
 
10924
+    p->type = type;
 
10925
+    p->next = NULL;
 
10926
+    return p;
 
10927
+}
 
10928
+
 
10929
+commandlist_t *new_if(test_t *t, commandlist_t *y, commandlist_t *n)
 
10930
+{
 
10931
+    commandlist_t *p = (commandlist_t *) xmalloc(sizeof(commandlist_t));
 
10932
+    p->type = IF;
 
10933
+    p->u.i.t = t;
 
10934
+    p->u.i.do_then = y;
 
10935
+    p->u.i.do_else = n;
 
10936
+    p->next = NULL;
 
10937
+    return p;
 
10938
+}
 
10939
+
 
10940
+void free_sl(stringlist_t *sl) 
 
10941
+{
 
10942
+    stringlist_t *sl2;
 
10943
+    
 
10944
+    while (sl != NULL) {
 
10945
+       sl2 = sl->next;
 
10946
+
 
10947
+       if (sl->s) free(sl->s);
 
10948
+
 
10949
+       free(sl);
 
10950
+       sl = sl2;
 
10951
+    }
 
10952
+}
 
10953
+
 
10954
+
 
10955
+void free_test(test_t *t);
 
10956
+
 
10957
+static void free_tl(testlist_t *tl)
 
10958
+{
 
10959
+    testlist_t *tl2;
 
10960
+
 
10961
+    while (tl) {
 
10962
+       tl2 = tl->next;
 
10963
+
 
10964
+       if (tl->t) free_test(tl->t);
 
10965
+
 
10966
+       free(tl);
 
10967
+       tl = tl2;
 
10968
+    }
 
10969
+}
 
10970
+
 
10971
+void free_test(test_t *t)
 
10972
+{
 
10973
+    if (t == NULL) return;
 
10974
+
 
10975
+    switch (t->type) {
 
10976
+    case ANYOF:
 
10977
+    case ALLOF:
 
10978
+       free_tl(t->u.tl);
 
10979
+       break;
 
10980
+
 
10981
+    case EXISTS:
 
10982
+       free_sl(t->u.sl);
 
10983
+       break;
 
10984
+
 
10985
+    case SIZE:
 
10986
+    case SFALSE:
 
10987
+    case STRUE:
 
10988
+       break;
 
10989
+
 
10990
+    case HEADER:
 
10991
+       free_sl(t->u.h.sl);
 
10992
+       free_sl(t->u.h.pl);
 
10993
+       
 
10994
+       break;
 
10995
+
 
10996
+    case ADDRESS:
 
10997
+       free_sl(t->u.ae.sl);
 
10998
+       free_sl(t->u.ae.pl);
 
10999
+       break;
 
11000
+
 
11001
+    case NOT:
 
11002
+       free_test(t->u.t);
 
11003
+       break;
 
11004
+    }
 
11005
+
 
11006
+    free(t);
 
11007
+}
 
11008
+
 
11009
+void free_tree(commandlist_t *cl)
 
11010
+{
 
11011
+    commandlist_t *cl2;
 
11012
+
 
11013
+    while (cl != NULL) {
 
11014
+       cl2 = cl->next;
 
11015
+       switch (cl->type) {
 
11016
+       case IF:
 
11017
+           free_test(cl->u.i.t);
 
11018
+           free_tree(cl->u.i.do_then);
 
11019
+           free_tree(cl->u.i.do_else);
 
11020
+           break;
 
11021
+
 
11022
+       case FILEINTO:
 
11023
+       case REDIRECT:
 
11024
+       case REJCT:
 
11025
+           if (cl->u.str) free(cl->u.str);
 
11026
+           break;
 
11027
+
 
11028
+       case VACATION:
 
11029
+           if (cl->u.v.subject) free(cl->u.v.subject);
 
11030
+           if (cl->u.v.addresses) free_sl(cl->u.v.addresses);
 
11031
+           if (cl->u.v.message) free(cl->u.v.message);
 
11032
+           break;
 
11033
+           
 
11034
+       case SETFLAG:
 
11035
+       case ADDFLAG:
 
11036
+       case REMOVEFLAG:
 
11037
+           free_sl(cl->u.sl);
 
11038
+           break;
 
11039
+
 
11040
+       case KEEP:
 
11041
+       case STOP:
 
11042
+       case DISCARD:
 
11043
+           break;
 
11044
+
 
11045
+       case NOTIFY:
 
11046
+           if (cl->u.n.method) free(cl->u.n.method);
 
11047
+           if (cl->u.n.id) free(cl->u.n.id);
 
11048
+           if (cl->u.n.options) free_sl(cl->u.n.options);
 
11049
+           if (cl->u.n.message) free(cl->u.n.message);
 
11050
+           break;
 
11051
+
 
11052
+       case DENOTIFY:
 
11053
+           if (cl->u.d.pattern) {
 
11054
+#ifdef ENABLE_REGEX
 
11055
+               if (cl->u.d.comptag == REGEX) {
 
11056
+                   regfree((regex_t *) cl->u.d.pattern);
 
11057
+               }
 
11058
+#endif
 
11059
+               free(cl->u.d.pattern);
 
11060
+           }
 
11061
+           break;
 
11062
+       }
 
11063
+
 
11064
+       free(cl);
 
11065
+       cl = cl2;
 
11066
+    }
 
11067
+}
 
11068
diff -r 894f003d9f5f src/lib-sieve/cmu/libsieve/tree.h
 
11069
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
11070
+++ b/src/lib-sieve/cmu/libsieve/tree.h Sun May 04 16:00:59 2008 +0200
 
11071
@@ -0,0 +1,139 @@
 
11072
+/* tree.h -- abstract syntax tree
 
11073
+ * Larry Greenfield
 
11074
+ * $Id$
 
11075
+ */
 
11076
+/***********************************************************
 
11077
+        Copyright 1999 by Carnegie Mellon University
 
11078
+
 
11079
+                      All Rights Reserved
 
11080
+
 
11081
+Permission to use, copy, modify, and distribute this software and its
 
11082
+documentation for any purpose and without fee is hereby granted,
 
11083
+provided that the above copyright notice appear in all copies and that
 
11084
+both that copyright notice and this permission notice appear in
 
11085
+supporting documentation, and that the name of Carnegie Mellon
 
11086
+University not be used in advertising or publicity pertaining to
 
11087
+distribution of the software without specific, written prior
 
11088
+permission.
 
11089
+
 
11090
+CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
 
11091
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
 
11092
+FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR
 
11093
+ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 
11094
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 
11095
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
 
11096
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
11097
+******************************************************************/
 
11098
+
 
11099
+#ifndef TREE_H
 
11100
+#define TREE_H
 
11101
+
 
11102
+#include "comparator.h"
 
11103
+
 
11104
+/* abstract syntax tree for sieve */
 
11105
+typedef struct Stringlist stringlist_t;
 
11106
+typedef struct Commandlist commandlist_t;
 
11107
+typedef struct Test test_t;
 
11108
+typedef struct Testlist testlist_t;
 
11109
+typedef struct Tag tag_t;
 
11110
+typedef struct Taglist taglist_t;
 
11111
+
 
11112
+struct Stringlist {
 
11113
+    char *s;
 
11114
+    stringlist_t *next;
 
11115
+};
 
11116
+
 
11117
 
11118
+struct Tag {
 
11119
+    int type;
 
11120
+    char *arg;
 
11121
+};
 
11122
+
 
11123
+struct Taglist {
 
11124
+    tag_t *t;
 
11125
+    taglist_t *next;
 
11126
+};
 
11127
+
 
11128
+struct Test {
 
11129
+    int type;
 
11130
+    union {
 
11131
+       testlist_t *tl; /* anyof, allof */
 
11132
+       stringlist_t *sl; /* exists */
 
11133
+       struct { /* it's a header test */
 
11134
+           int comptag;
 
11135
+           char * comparator;
 
11136
+           int relation;
 
11137
+           void *comprock;
 
11138
+           stringlist_t *sl;
 
11139
+           stringlist_t *pl;
 
11140
+       } h;
 
11141
+       struct { /* it's an address or envelope test */
 
11142
+           int comptag;
 
11143
+           char * comparator;
 
11144
+           int relation; 
 
11145
+           void *comprock;
 
11146
+           stringlist_t *sl;
 
11147
+           stringlist_t *pl;
 
11148
+            int addrpart;
 
11149
+       } ae; 
 
11150
+       test_t *t; /* not */
 
11151
+       struct { /* size */
 
11152
+           int t; /* tag */
 
11153
+           int n; /* param */
 
11154
+       } sz;
 
11155
+    } u;
 
11156
+};
 
11157
+
 
11158
+struct Testlist {
 
11159
+    test_t *t;
 
11160
+    testlist_t *next;
 
11161
+};
 
11162
+
 
11163
+struct Commandlist {
 
11164
+    int type;
 
11165
+    union {
 
11166
+        char *str;
 
11167
+       stringlist_t *sl; /* the parameters */
 
11168
+       struct { /* it's an if statement */
 
11169
+           test_t *t;
 
11170
+           commandlist_t *do_then;
 
11171
+           commandlist_t *do_else;
 
11172
+       } i;
 
11173
+       struct { /* it's a vacation action */
 
11174
+           char *subject;
 
11175
+           int days;
 
11176
+           stringlist_t *addresses;
 
11177
+           char *message;
 
11178
+           int mime;
 
11179
+       } v;
 
11180
+       struct { /* it's a notify action */
 
11181
+           char *method;
 
11182
+           char *id;
 
11183
+           stringlist_t *options;
 
11184
+           int priority;
 
11185
+           char *message;
 
11186
+       } n;
 
11187
+       struct { /* it's a denotify action */
 
11188
+           int comptag;
 
11189
+           int relation;
 
11190
+           void *comprock;
 
11191
+           void *pattern;
 
11192
+           int priority;
 
11193
+       } d;
 
11194
+    } u;
 
11195
+    struct Commandlist *next;
 
11196
+};
 
11197
+
 
11198
+stringlist_t *new_sl(char *s, stringlist_t *n);
 
11199
+tag_t *new_tag(int type, char *s);
 
11200
+taglist_t *new_taglist(tag_t *t, taglist_t *n);
 
11201
+test_t *new_test(int type);
 
11202
+testlist_t *new_testlist(test_t *t, testlist_t *n);
 
11203
+commandlist_t *new_command(int type);
 
11204
+commandlist_t *new_if(test_t *t, commandlist_t *y, commandlist_t *n);
 
11205
+
 
11206
+void free_sl(stringlist_t *sl);
 
11207
+void free_test(test_t *t);
 
11208
+void free_tree(commandlist_t *cl);
 
11209
+
 
11210
+#endif
 
11211
diff -r 894f003d9f5f src/lib-sieve/cmu/map.c
 
11212
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
11213
+++ b/src/lib-sieve/cmu/map.c   Sun May 04 16:00:59 2008 +0200
 
11214
@@ -0,0 +1,55 @@
 
11215
+#include "lib.h"
 
11216
+#include "map.h"
 
11217
+
 
11218
+#include <unistd.h>
 
11219
+
 
11220
+static ssize_t read_full_n(int fd, void *data, size_t size)
 
11221
+{
 
11222
+       ssize_t ret, all_ret = 0;
 
11223
+
 
11224
+       while (size > 0) {
 
11225
+               ret = read(fd, data, size);
 
11226
+               if (ret <= 0)
 
11227
+                       return ret;
 
11228
+
 
11229
+               data = PTR_OFFSET(data, ret);
 
11230
+               all_ret += ret;
 
11231
+               size -= ret;
 
11232
+       }
 
11233
+
 
11234
+       return all_ret;
 
11235
+}
 
11236
+
 
11237
+void map_refresh(int fd, int onceonly __attr_unused__, const char **base,
 
11238
+                unsigned long *len, unsigned long newlen,
 
11239
+                const char *name, const char *mboxname __attr_unused__)
 
11240
+{
 
11241
+       ssize_t ret;
 
11242
+       void *p;
 
11243
+
 
11244
+       if (newlen == 0) {
 
11245
+               /* the file is a broken zero-byte file */
 
11246
+               *len = 0;
 
11247
+               return;
 
11248
+       }
 
11249
+
 
11250
+       *base = p = i_malloc(newlen);
 
11251
+       *len = newlen;
 
11252
+
 
11253
+       ret = read_full_n(fd, p, newlen);
 
11254
+       if (ret < 0) {
 
11255
+               i_error("read_full_n(%s) failed: %m", name);
 
11256
+               ret = 0;
 
11257
+       }
 
11258
+
 
11259
+       *len = ret;
 
11260
+}
 
11261
+
 
11262
+void map_free(const char **base, unsigned long *len __attr_unused__)
 
11263
+{
 
11264
+       char *x = (char *) *base;
 
11265
+
 
11266
+       i_free(x);
 
11267
+       *base = NULL;
 
11268
+}
 
11269
+
 
11270
diff -r 894f003d9f5f src/lib-sieve/cmu/map.h
 
11271
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
11272
+++ b/src/lib-sieve/cmu/map.h   Sun May 04 16:00:59 2008 +0200
 
11273
@@ -0,0 +1,10 @@
 
11274
+#ifndef __MAP_H
 
11275
+#define __MAP_H
 
11276
+
 
11277
+extern void map_refresh(int fd, int onceonly, const char **base,
 
11278
+                       unsigned long *len, unsigned long newlen,
 
11279
+                       const char *name, const char *mboxname);
 
11280
+
 
11281
+extern void map_free(const char **base, unsigned long *len);
 
11282
+
 
11283
+#endif
 
11284
diff -r 894f003d9f5f src/lib-sieve/cmu/xmalloc.h
 
11285
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
11286
+++ b/src/lib-sieve/cmu/xmalloc.h       Sun May 04 16:00:59 2008 +0200
 
11287
@@ -0,0 +1,26 @@
 
11288
+#ifndef __XMALLOC_H
 
11289
+#define __XMALLOC_H
 
11290
+
 
11291
+#include <stdlib.h>
 
11292
+#include <string.h>
 
11293
+
 
11294
+#define xmalloc(n) malloc(n)
 
11295
+#define xrealloc(n, m) realloc(n, m)
 
11296
+#define xzmalloc(n) calloc(n, 1)
 
11297
+#define xstrdup(s) strdup(s)
 
11298
+
 
11299
+/* missing headers.. */
 
11300
+#include <sys/types.h>
 
11301
+#include <netinet/in.h>
 
11302
+#include <regex.h>
 
11303
+#include <fcntl.h>
 
11304
+
 
11305
+/* dovecot kludges */
 
11306
+#include "lib.h"
 
11307
+
 
11308
+/* we don't have strlcpy, but strocpy is the same except for return value */
 
11309
+#define strlcpy strocpy
 
11310
+
 
11311
+#define lcase str_lcase
 
11312
+
 
11313
+#endif
 
11314
diff -r 894f003d9f5f src/lib-sieve/sieve-implementation-private.h
 
11315
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
11316
+++ b/src/lib-sieve/sieve-implementation-private.h      Sun May 04 16:00:59 2008 +0200
 
11317
@@ -0,0 +1,62 @@
 
11318
+#ifndef __SIEVE_IMPLEMENTATION_PRIVATE_H
 
11319
+#define        __SIEVE_IMPLEMENTATION_PRIVATE_H
 
11320
+
 
11321
+#include "lib.h"
 
11322
+#include "mail-storage.h"
 
11323
+
 
11324
+struct sieve_script;
 
11325
+
 
11326
+#define DUPLICATE_DEFAULT_KEEP (3600 * 24)
 
11327
+
 
11328
+struct sieve_implementation_vfuncs {
 
11329
+       int (*compile) 
 
11330
+               (struct sieve_script *script, bool verify_only);
 
11331
+       int (*run) 
 
11332
+               (struct sieve_script *script, void *context);
 
11333
+       const char *(*get_capabilities) ();
 
11334
+};
 
11335
+
 
11336
+struct sieve_implementation {
 
11337
+       const char *name;
 
11338
+       struct sieve_implementation_vfuncs v;
 
11339
+};
 
11340
+
 
11341
+/* Error management */
 
11342
+void sieve_clear_error(void);
 
11343
+void sieve_set_error(const char *fmt, ...);
 
11344
+void sieve_set_internal_error(void);
 
11345
+void sieve_set_critical(const char *fmt, ...);
 
11346
+
 
11347
+void sieve_implementation_register(struct sieve_implementation *sieveimpl);
 
11348
+
 
11349
+void sieve_implementation_unregister(struct sieve_implementation *sieveimpl);
 
11350
+
 
11351
+void sieve_register_implementations(void);
 
11352
+
 
11353
+const char *const *sieve_runenv_get_mail_headers
 
11354
+       (void *context, const char *field);
 
11355
+const char *sieve_runenv_get_mail_first_header
 
11356
+       (void *context, const char *field);
 
11357
+uoff_t sieve_runenv_get_mail_size
 
11358
+       (void *context);
 
11359
+int sieve_runenv_get_envelope
 
11360
+  (void *context, const char *field, array_t *contents);
 
11361
+
 
11362
+int sieve_runenv_is_duplicate
 
11363
+       (void *context, const void *id, size_t id_size);
 
11364
+void sieve_runenv_mark_duplicate
 
11365
+  (void *context, const void *id, size_t id_size, time_t interval);
 
11366
+
 
11367
+int sieve_runenv_send_message
 
11368
+  (void *context, const char *from, const char *to, const char *subject,
 
11369
+   bool mime, const char *msg, const char **outmsgid);
 
11370
+int sieve_runenv_send_rejection
 
11371
+  (void *context, const char *reason);
 
11372
+int sieve_runenv_send_forward
 
11373
+       (void *context, const char *forwardto);
 
11374
+int sieve_runenv_mail_save
 
11375
+  (void *context, const char *mailbox, char **flags, unsigned int nflags);
 
11376
+
 
11377
+#include "sieve-implementation.h"
 
11378
+
 
11379
+#endif
 
11380
diff -r 894f003d9f5f src/lib-sieve/sieve-implementation.c
 
11381
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
11382
+++ b/src/lib-sieve/sieve-implementation.c      Sun May 04 16:00:59 2008 +0200
 
11383
@@ -0,0 +1,235 @@
 
11384
+#include "lib.h"
 
11385
+#include "array.h"
 
11386
+#include "ioloop.h"
 
11387
+#include "sieve-implementation-private.h"
 
11388
+#include "sieve-implementation.h"
 
11389
+
 
11390
+#include <time.h>
 
11391
+
 
11392
+/* Message to show to users when critical error occurs */
 
11393
+#define CRITICAL_MSG \
 
11394
+  "Internal error occurred. Refer to server log for more information."
 
11395
+#define CRITICAL_MSG_STAMP CRITICAL_MSG " [%Y-%m-%d %H:%M:%S]"
 
11396
+
 
11397
+static array_t ARRAY_DEFINE(implementations, struct sieve_implementation *);
 
11398
+
 
11399
+static struct sieve_implementation *cursieveimpl = NULL;
 
11400
+static struct sieve_runtime_environment *runenv = NULL;
 
11401
+static char *sieve_error;
 
11402
+
 
11403
+void sieve_deinit(void)
 
11404
+{
 
11405
+       if (array_is_created(&implementations))
 
11406
+               array_free(&implementations);
 
11407
+}
 
11408
+
 
11409
+void sieve_implementation_register(struct sieve_implementation *sieveimpl)
 
11410
+{
 
11411
+       /* append it after the list, so the autodetection order is correct */
 
11412
+       array_append(&implementations, &sieveimpl, 1);
 
11413
+}
 
11414
+
 
11415
+void sieve_implementation_unregister(struct sieve_implementation *sieveimpl)
 
11416
+{
 
11417
+       struct sieve_implementation *const *impls;
 
11418
+       unsigned int i, count;
 
11419
+
 
11420
+       impls = array_get(&implementations, &count);
 
11421
+       for (i = 0; i < count; i++) {
 
11422
+               if (impls[i] == sieveimpl) {
 
11423
+                       array_delete(&implementations, i, 1);
 
11424
+                       break;
 
11425
+               }
 
11426
+       }
 
11427
+}
 
11428
+
 
11429
+/* FIXME: Make this function dependent on ./configure
 
11430
+ */
 
11431
+extern struct sieve_implementation cmu_sieve;
 
11432
+void sieve_register_implementations()
 
11433
+{
 
11434
+       sieve_implementation_register(&cmu_sieve);
 
11435
+}
 
11436
+
 
11437
+void sieve_set_runtime_environment(struct sieve_runtime_environment *env) 
 
11438
+{
 
11439
+       runenv = env;
 
11440
+}
 
11441
+
 
11442
+void sieve_init(void)
 
11443
+{
 
11444
+       ARRAY_CREATE(&implementations, default_pool, struct sieve_implementation *, 8);
 
11445
+       
 
11446
+       sieve_register_implementations();
 
11447
+}
 
11448
+
 
11449
+/* Sets the active implementation */
 
11450
+int sieve_set_implementation(const char *name)
 
11451
+{
 
11452
+       struct sieve_implementation *const *impls;
 
11453
+       unsigned int i, count;
 
11454
+
 
11455
+       i_assert(name != NULL);
 
11456
+
 
11457
+       impls = array_get(&implementations, &count);
 
11458
+       for (i = 0; i < count; i++) {
 
11459
+               if (strcasecmp(impls[i]->name, name) == 0) {
 
11460
+                       cursieveimpl = impls[i];
 
11461
+                       return 0;
 
11462
+               }
 
11463
+       }
 
11464
+
 
11465
+       return -1;
 
11466
+}                      
 
11467
+
 
11468
+void sieve_clear_error(void)
 
11469
+{
 
11470
+       i_free(sieve_error);
 
11471
+       sieve_error = NULL;
 
11472
+}
 
11473
+
 
11474
+void sieve_set_error(const char *fmt, ...)
 
11475
+{
 
11476
+       va_list va;
 
11477
+
 
11478
+       sieve_clear_error();
 
11479
+
 
11480
+       if (fmt != NULL) {
 
11481
+               va_start(va, fmt);
 
11482
+               sieve_error = i_strdup_vprintf(fmt, va);
 
11483
+               va_end(va);
 
11484
+       }
 
11485
+}
 
11486
+
 
11487
+void sieve_set_internal_error(void)
 
11488
+{
 
11489
+       struct tm *tm;
 
11490
+       char str[256];
 
11491
+       
 
11492
+       tm = localtime(&ioloop_time);
 
11493
+       
 
11494
+       i_free(sieve_error);
 
11495
+       sieve_error =
 
11496
+         strftime(str, sizeof(str), CRITICAL_MSG_STAMP, tm) > 0 ?
 
11497
+         i_strdup(str) : i_strdup(CRITICAL_MSG);
 
11498
+}
 
11499
+
 
11500
+void sieve_set_critical(const char *fmt, ...)
 
11501
+{
 
11502
+       va_list va;
 
11503
+  
 
11504
+       sieve_clear_error();
 
11505
+       if (fmt != NULL) {
 
11506
+               va_start(va, fmt);
 
11507
+               i_error("%s", t_strdup_vprintf(fmt, va));
 
11508
+               va_end(va);
 
11509
+               
 
11510
+               /* critical errors may contain sensitive data, so let user
 
11511
+                  see only "Internal error" with a timestamp to make it
 
11512
+                  easier to look from log files the actual error message. */
 
11513
+               sieve_set_internal_error();
 
11514
+       }
 
11515
+}
 
11516
+
 
11517
+const char *sieve_get_last_error(void)
 
11518
+{
 
11519
+       /* We get here only in error situations, so we have to return some
 
11520
+          error. If storage->error is NULL, it means we forgot to set it at
 
11521
+          some point.. */
 
11522
+       return sieve_error != NULL ? sieve_error : "Unknown error";
 
11523
+}
 
11524
+
 
11525
+int sieve_compile(struct sieve_script *script, bool verify_only) 
 
11526
+{
 
11527
+       i_assert(cursieveimpl != NULL);
 
11528
+       return cursieveimpl->v.compile(script, verify_only);
 
11529
+}
 
11530
+
 
11531
+int sieve_run(struct sieve_script *script, void *context)
 
11532
+{
 
11533
+       i_assert(cursieveimpl != NULL);
 
11534
+       return cursieveimpl->v.run(script, context);
 
11535
+}
 
11536
+
 
11537
+const char *sieve_get_capabilities(void)
 
11538
+{
 
11539
+       i_assert(cursieveimpl != NULL);
 
11540
+       return cursieveimpl->v.get_capabilities();
 
11541
+}
 
11542
+
 
11543
+/* Runtime environment */
 
11544
+
 
11545
+const char *const *sieve_runenv_get_mail_headers
 
11546
+  (void *context, const char *field)
 
11547
+{
 
11548
+       i_assert(runenv != NULL);
 
11549
+       return runenv->get_mail_headers(context, field);
 
11550
+}
 
11551
+
 
11552
+const char *sieve_runenv_get_mail_first_header(void *context, const char *field)
 
11553
+{
 
11554
+       const char *const *list = sieve_runenv_get_mail_headers(context, field);
 
11555
+       return list == NULL ? NULL : list[0];
 
11556
+}
 
11557
+
 
11558
+uoff_t sieve_runenv_get_mail_size
 
11559
+  (void *context)
 
11560
+{
 
11561
+       i_assert(runenv != NULL);
 
11562
+       return runenv->get_mail_size(context);
 
11563
+}
 
11564
+
 
11565
+int sieve_runenv_is_duplicate
 
11566
+  (void *context, const void *id, size_t id_size)
 
11567
+{
 
11568
+       i_assert(runenv != NULL);
 
11569
+       return runenv->is_duplicate(context, id, id_size);
 
11570
+}
 
11571
+
 
11572
+void sieve_runenv_mark_duplicate
 
11573
+  (void *context, const void *id, size_t id_size, time_t interval)
 
11574
+{
 
11575
+       i_assert(runenv != NULL);
 
11576
+       runenv->mark_duplicate(context, id, id_size, interval);
 
11577
+}
 
11578
+
 
11579
+int sieve_runenv_send_message
 
11580
+  (void *context, const char *from, const char *to, const char *subject,
 
11581
+   bool mime, const char *msg, const char **outmsgid)
 
11582
+{
 
11583
+       i_assert(runenv != NULL);
 
11584
+
 
11585
+       return runenv->send_message
 
11586
+         (context, from, to, subject, mime, msg, outmsgid);
 
11587
+}
 
11588
+
 
11589
+int sieve_runenv_get_envelope
 
11590
+       (void *context, const char *field, array_t *contents)
 
11591
+{
 
11592
+       i_assert(runenv != NULL);
 
11593
+
 
11594
+       return runenv->get_envelope(context, field, contents);
 
11595
+}
 
11596
+
 
11597
+int sieve_runenv_send_rejection
 
11598
+       (void *context, const char *reason)
 
11599
+{
 
11600
+       i_assert(runenv != NULL);
 
11601
+
 
11602
+       return runenv->send_rejection(context, reason);
 
11603
+}
 
11604
+
 
11605
+int sieve_runenv_send_forward(void *context, const char *forwardto)
 
11606
+{
 
11607
+       i_assert(runenv != NULL);
 
11608
+
 
11609
+       return runenv->send_forward(context, forwardto);
 
11610
+}
 
11611
+
 
11612
+int sieve_runenv_mail_save
 
11613
+  (void *context, const char *mailbox, char **flags, unsigned int nflags)
 
11614
+{
 
11615
+       i_assert(runenv != NULL);
 
11616
+
 
11617
+       return runenv->mail_save(context, mailbox, flags, nflags);
 
11618
+}
 
11619
diff -r 894f003d9f5f src/lib-sieve/sieve-implementation.h
 
11620
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
11621
+++ b/src/lib-sieve/sieve-implementation.h      Sun May 04 16:00:59 2008 +0200
 
11622
@@ -0,0 +1,46 @@
 
11623
+#ifndef __SIEVE_IMPLEMENTATION_H
 
11624
+#define __SIEVE_IMPLEMENTATION_H
 
11625
+
 
11626
+struct sieve_script;
 
11627
+
 
11628
+struct sieve_runtime_environment {
 
11629
+       const char *const *(*get_mail_headers)
 
11630
+               (void *context, const char *field);
 
11631
+       uoff_t (*get_mail_size)
 
11632
+               (void *context);
 
11633
+       int (*get_envelope)
 
11634
+               (void *context, const char *field, array_t *contents);
 
11635
+
 
11636
+       int (*is_duplicate)
 
11637
+               (void *context, const void *id, size_t id_size);
 
11638
+       void (*mark_duplicate)
 
11639
+               (void *context, const void *id, size_t id_size, time_t interval);
 
11640
+
 
11641
+       int (*send_message)
 
11642
+               (void *context, const char *from, const char *to, const char *subject,
 
11643
+               bool mime, const char *msg, const char **outmsgid);
 
11644
+       int (*send_rejection)
 
11645
+               (void *context, const char *reason);
 
11646
+       int (*send_forward)
 
11647
+               (void *context, const char *forwardto);
 
11648
+       int (*mail_save)
 
11649
+               (void *context, const char *mailbox, char **flags, unsigned int nflags);
 
11650
+};
 
11651
+
 
11652
+void sieve_init(void);
 
11653
+void sieve_deinit(void);
 
11654
+
 
11655
+int sieve_set_implementation(const char *name);
 
11656
+
 
11657
+void sieve_set_runtime_environment(struct sieve_runtime_environment *env);
 
11658
+
 
11659
+const char *sieve_get_last_error(void);
 
11660
+
 
11661
+int sieve_compile(struct sieve_script *script, bool verify_only);
 
11662
+
 
11663
+int sieve_run(struct sieve_script *script, void *context);
 
11664
+
 
11665
+const char *sieve_get_capabilities(void);
 
11666
+
 
11667
+#endif
 
11668
+
 
11669
diff -r 894f003d9f5f src/lib-sievestorage/Makefile.am
 
11670
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
11671
+++ b/src/lib-sievestorage/Makefile.am  Sun May 04 16:00:59 2008 +0200
 
11672
@@ -0,0 +1,19 @@
 
11673
+noinst_LIBRARIES = libsievestorage.a
 
11674
+
 
11675
+INCLUDES = \
 
11676
+       -I$(top_srcdir)/src/lib \
 
11677
+       -I$(top_srcdir)/src/lib-mail \
 
11678
+  -I$(dovecotsievedir)/src/libsieve
 
11679
+
 
11680
+libsievestorage_a_SOURCES = \
 
11681
+       sieve-save.c \
 
11682
+       sieve-script.c \
 
11683
+       sieve-list.c \
 
11684
+       sieve-storage.c 
 
11685
+
 
11686
+noinst_HEADERS = \
 
11687
+       sieve-save.h \
 
11688
+       sieve-script.h \
 
11689
+       sieve-list.h \
 
11690
+       sieve-storage.h \
 
11691
+       sieve-storage-private.h 
 
11692
diff -r 894f003d9f5f src/lib-sievestorage/sieve-list.c
 
11693
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
11694
+++ b/src/lib-sievestorage/sieve-list.c Sun May 04 16:00:59 2008 +0200
 
11695
@@ -0,0 +1,116 @@
 
11696
+#include "lib.h"
 
11697
+#include "str.h"
 
11698
+#include "sieve-storage-private.h"
 
11699
+#include "sieve-script.h"
 
11700
+#include "sieve-list.h"
 
11701
+
 
11702
+#include <stdio.h>
 
11703
+#include <stdlib.h>
 
11704
+#include <sys/types.h>
 
11705
+#include <dirent.h>
 
11706
+#include <sys/stat.h>
 
11707
+
 
11708
+struct sieve_list_context {
 
11709
+       pool_t pool;
 
11710
+       struct sieve_storage *storage;
 
11711
+
 
11712
+       const char *active;
 
11713
+       const char *dir;
 
11714
+       DIR *dirp;
 
11715
+
 
11716
+       unsigned int seen_active:1; // Just present for assertions
 
11717
+};
 
11718
+
 
11719
+struct sieve_list_context *sieve_storage_list_init
 
11720
+       (struct sieve_storage *storage)
 
11721
+{      
 
11722
+       struct sieve_list_context *ctx;
 
11723
+       const char *active;
 
11724
+       pool_t pool;
 
11725
+       DIR *dirp;
 
11726
+
 
11727
+       /* Open the directory */
 
11728
+       if ( (dirp = opendir(storage->dir)) == NULL ) {
 
11729
+               sieve_storage_set_critical(storage, "opendir(%s) failed: %m",
 
11730
+                                          storage->dir);
 
11731
+               return NULL;
 
11732
+       }
 
11733
+
 
11734
+       t_push();
 
11735
+
 
11736
+       /* Get the name of the active script */
 
11737
+       if ( (active = sieve_storage_get_active_scriptname(storage)) 
 
11738
+               == NULL ) {
 
11739
+               t_pop();
 
11740
+               return NULL;
 
11741
+       }
 
11742
+
 
11743
+       pool = pool_alloconly_create("sieve_list_context", 4096);
 
11744
+       ctx = p_new(pool, struct sieve_list_context, 1);
 
11745
+       ctx->pool = pool;
 
11746
+       ctx->storage = storage;
 
11747
+       ctx->dirp = dirp;
 
11748
+       ctx->active = p_strdup(pool, active);
 
11749
+       ctx->seen_active = FALSE;
 
11750
+
 
11751
+       t_pop();
 
11752
+
 
11753
+       return ctx;
 
11754
+}
 
11755
+
 
11756
+const char *sieve_storage_list_next
 
11757
+       (struct sieve_list_context *ctx, bool *active)
 
11758
+{
 
11759
+       const struct sieve_storage *storage = ctx->storage;
 
11760
+       struct dirent *dp;
 
11761
+       const char *scriptname;
 
11762
+
 
11763
+       *active = FALSE;
 
11764
+
 
11765
+       for (;;) {
 
11766
+               if ( (dp = readdir(ctx->dirp)) == NULL )
 
11767
+                       return NULL;
 
11768
+
 
11769
+               scriptname = sieve_storage_file_get_scriptname
 
11770
+                       (storage, dp->d_name);  
 
11771
+               
 
11772
+               if (scriptname != NULL ) {
 
11773
+                       /* Don't list our active sieve script link if the link 
 
11774
+                        * resides in the script dir (generally a bad idea).
 
11775
+                        */
 
11776
+                       if ( *(storage->link_path) == '\0' && 
 
11777
+                               strcmp(storage->active_fname, dp->d_name) == 0 )
 
11778
+                               continue;
 
11779
+               
 
11780
+                       break;
 
11781
+               }
 
11782
+       }
 
11783
+
 
11784
+       if ( ctx->active != NULL && 
 
11785
+               strcmp(scriptname, ctx->active) == 0 ) {
 
11786
+               *active = TRUE;
 
11787
+               ctx->active = NULL;
 
11788
+       }
 
11789
+
 
11790
+       return scriptname;
 
11791
+}
 
11792
+
 
11793
+int sieve_storage_list_deinit(struct sieve_list_context **ctx)
 
11794
+{
 
11795
+       if (closedir((*ctx)->dirp) < 0) {
 
11796
+               sieve_storage_set_critical((*ctx)->storage, "closedir(%s) failed: %m",
 
11797
+                                          (*ctx)->storage->dir);
 
11798
+
 
11799
+               pool_unref((*ctx)->pool);
 
11800
+               *ctx = NULL;
 
11801
+               return -1;
 
11802
+       }
 
11803
+
 
11804
+       pool_unref((*ctx)->pool);
 
11805
+       *ctx = NULL;
 
11806
+       return 1;
 
11807
+}
 
11808
+
 
11809
+
 
11810
+       
 
11811
+    
 
11812
diff -r 894f003d9f5f src/lib-sievestorage/sieve-list.h
 
11813
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
11814
+++ b/src/lib-sievestorage/sieve-list.h Sun May 04 16:00:59 2008 +0200
 
11815
@@ -0,0 +1,30 @@
 
11816
+#ifndef __SIEVE_LIST_H
 
11817
+#define __SIEVE_LIST_H
 
11818
+
 
11819
+#include "lib.h"
 
11820
+#include "str.h"
 
11821
+#include "sieve-storage.h"
 
11822
+#include "sieve-list.h"
 
11823
+
 
11824
+#include <stdio.h>
 
11825
+#include <stdlib.h>
 
11826
+#include <dirent.h>
 
11827
+#include <sys/stat.h>
 
11828
+
 
11829
+struct sieve_list_context;
 
11830
+
 
11831
+/* Create a context for listing the scripts in the storage */
 
11832
+struct sieve_list_context *sieve_storage_list_init
 
11833
+       (struct sieve_storage *storage);
 
11834
+
 
11835
+/* Get the next script in the storage. */
 
11836
+const char *sieve_storage_list_next(struct sieve_list_context *ctx, bool *active);
 
11837
+
 
11838
+/* Destroy the listing context */
 
11839
+int sieve_storage_list_deinit(struct sieve_list_context **ctx);
 
11840
+
 
11841
+#endif
 
11842
+
 
11843
+
 
11844
+       
 
11845
+    
 
11846
diff -r 894f003d9f5f src/lib-sievestorage/sieve-save.c
 
11847
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
11848
+++ b/src/lib-sievestorage/sieve-save.c Sun May 04 16:00:59 2008 +0200
 
11849
@@ -0,0 +1,322 @@
 
11850
+#include "lib.h"
 
11851
+#include "hostpid.h"
 
11852
+#include "ioloop.h"
 
11853
+#include "array.h"
 
11854
+#include "buffer.h"
 
11855
+#include "ostream.h"
 
11856
+#include "ostream-crlf.h"
 
11857
+#include "str.h"
 
11858
+#include "sieve-storage-private.h"
 
11859
+#include "sieve-save.h"
 
11860
+#include "sieve-script.h"
 
11861
+
 
11862
+#include <stdio.h>
 
11863
+#include <stdlib.h>
 
11864
+#include <unistd.h>
 
11865
+#include <fcntl.h>
 
11866
+#include <utime.h>
 
11867
+#include <sys/stat.h>
 
11868
+
 
11869
+struct sieve_save_context {
 
11870
+       pool_t pool;
 
11871
+
 
11872
+       struct sieve_storage *storage;
 
11873
+       const char *scriptname;
 
11874
+       struct sieve_script *scriptobject;
 
11875
+
 
11876
+       struct istream *input;
 
11877
+       struct ostream *output;
 
11878
+       int fd;
 
11879
+       const char *tmp_path;
 
11880
+
 
11881
+       unsigned int failed:1;
 
11882
+       unsigned int moving:1;
 
11883
+       unsigned int finished:1;
 
11884
+};
 
11885
+
 
11886
+static const char *sieve_generate_tmp_filename(const char *scriptname, const struct timeval *tv)
 
11887
+{
 
11888
+       static unsigned int create_count = 0;
 
11889
+       static time_t first_stamp = 0;
 
11890
+
 
11891
+       if (first_stamp == 0 || first_stamp == ioloop_time) {
 
11892
+               /* it's possible that within last second another process had
 
11893
+                  the same PID as us. Use usecs to make sure we don't create
 
11894
+                  duplicate base name. */
 
11895
+               first_stamp = ioloop_time;
 
11896
+               return t_strdup_printf
 
11897
+                 ("%s-%s.P%sQ%uM%s.%s",
 
11898
+                  scriptname,
 
11899
+                  dec2str(tv->tv_sec), my_pid,
 
11900
+                  create_count++,
 
11901
+                  dec2str(tv->tv_usec), my_hostname);
 
11902
+       } else {
 
11903
+               /* Don't bother with usecs. Saves a bit space :) */
 
11904
+               return t_strdup_printf
 
11905
+                 ("%s-%s.P%sQ%u.%s",
 
11906
+                  scriptname,
 
11907
+                  dec2str(tv->tv_sec), my_pid,
 
11908
+                  create_count++, my_hostname);
 
11909
+       }
 
11910
+}
 
11911
+
 
11912
+static int sieve_create_tmp
 
11913
+(struct sieve_storage *storage, const char *scriptname, const char **fpath_r)
 
11914
+{
 
11915
+       const char *path, *tmp_fname;
 
11916
+       struct stat st;
 
11917
+       struct timeval *tv, tv_now;
 
11918
+       pool_t pool;
 
11919
+       int fd;
 
11920
+
 
11921
+       tv = &ioloop_timeval;
 
11922
+       pool = pool_alloconly_create("script_tmp", 4096);
 
11923
+       for (;;) {
 
11924
+               p_clear(pool);
 
11925
+               tmp_fname = sieve_generate_tmp_filename(scriptname, tv);
 
11926
+
 
11927
+               path = p_strconcat(pool, storage->dir, "/tmp/", tmp_fname, ".sieve", NULL);
 
11928
+               if ( stat(path, &st) < 0 ) {
 
11929
+                       if ( errno == ENOENT) {
 
11930
+                               /* NICE! doesn't exist */
 
11931
+                               fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0600);
 
11932
+                 
 
11933
+                               /* Something went wrong */
 
11934
+                               if (fd != -1 || errno != EEXIST)
 
11935
+                                       break;
 
11936
+                       } else {
 
11937
+                               sieve_storage_set_critical(storage,
 
11938
+                       "stat(%s) failed: %m", path);
 
11939
+                               return -1;
 
11940
+                       }
 
11941
+               }
 
11942
+
 
11943
+               /* Wait and try again - very unlikely */
 
11944
+               sleep(2);
 
11945
+               tv = &tv_now;
 
11946
+               if (gettimeofday(&tv_now, NULL) < 0)
 
11947
+                       i_fatal("gettimeofday(): %m");
 
11948
+       }
 
11949
+       
 
11950
+       *fpath_r = t_strdup(path);
 
11951
+       if (fd == -1) {
 
11952
+               if (ENOSPACE(errno)) {
 
11953
+                       sieve_storage_set_error(storage,
 
11954
+                               "Not enough disk space");
 
11955
+               } else {
 
11956
+                       sieve_storage_set_critical(storage,
 
11957
+                               "open(%s) failed: %m", path);
 
11958
+        }
 
11959
+    } 
 
11960
+
 
11961
+       pool_unref(pool);
 
11962
+       return fd;
 
11963
+}
 
11964
+
 
11965
+static int sieve_script_move(struct sieve_save_context *ctx,
 
11966
+  const char *dst)
 
11967
+{
 
11968
+       int failed;
 
11969
+
 
11970
+       t_push();
 
11971
+
 
11972
+       /* Using rename() to ensure existing files are replaced
 
11973
+        * without conflicts with other processes using the same
 
11974
+        * file. The kernel wont fully delete the original until
 
11975
+        * all processes have closed the file.
 
11976
+        */
 
11977
+       if (rename(ctx->tmp_path, dst) == 0)
 
11978
+               failed = FALSE;
 
11979
+       else {
 
11980
+               failed = TRUE;
 
11981
+               if (ENOSPACE(errno)) {
 
11982
+                       sieve_storage_set_error
 
11983
+                         (ctx->storage, "Not enough disk space");
 
11984
+               } else {
 
11985
+                       sieve_storage_set_critical
 
11986
+                         (ctx->storage, "link(%s, %s) failed: %m", ctx->tmp_path, dst);
 
11987
+               }
 
11988
+       }
 
11989
+
 
11990
+       /* Always destroy temp file */
 
11991
+       (void)unlink(ctx->tmp_path);
 
11992
+
 
11993
+       t_pop();
 
11994
+       return !failed;
 
11995
+}
 
11996
+
 
11997
+struct sieve_save_context *
 
11998
+sieve_storage_save_init(struct sieve_storage *storage,
 
11999
+       const char *scriptname, struct istream *input)
 
12000
+{
 
12001
+       struct sieve_save_context *ctx;
 
12002
+       pool_t pool;
 
12003
+       struct ostream *output;
 
12004
+       const char *path;
 
12005
+
 
12006
+       /* Prevent overwriting the active script link when it resides in the 
 
12007
+        * sieve storage directory.
 
12008
+        */
 
12009
+       if ( *(storage->link_path) == '\0' ) {
 
12010
+               const char *svext;
 
12011
+               size_t namelen;
 
12012
+
 
12013
+               svext = strrchr(storage->active_fname, '.');
 
12014
+               namelen = svext - storage->active_fname;
 
12015
+               if ( svext != NULL && strncmp(svext+1, "sieve", 5) == 0 &&
 
12016
+                       strlen(scriptname) == namelen && 
 
12017
+                       strncmp(scriptname, storage->active_fname, namelen) == 0 ) 
 
12018
+               {
 
12019
+                       sieve_storage_set_error(
 
12020
+                               storage, "Script name '%s' is reserved for internal use.", 
 
12021
+                               scriptname); 
 
12022
+                       return NULL;
 
12023
+               }
 
12024
+       }
 
12025
+
 
12026
+       pool = pool_alloconly_create("sieve_save_context", 4096);
 
12027
+       ctx = p_new(pool, struct sieve_save_context, 1);
 
12028
+       ctx->pool = pool;
 
12029
+       ctx->storage = storage;
 
12030
+       ctx->scriptname = scriptname;
 
12031
+       ctx->scriptobject = NULL;
 
12032
+
 
12033
+       t_push();
 
12034
+
 
12035
+       ctx->fd = sieve_create_tmp(storage, scriptname, &path);
 
12036
+       if (ctx->fd == -1) {
 
12037
+               ctx->failed = TRUE;
 
12038
+               t_pop();
 
12039
+               pool_unref(pool);
 
12040
+               return NULL;
 
12041
+       }
 
12042
+
 
12043
+       ctx->input = input;
 
12044
+
 
12045
+       output = o_stream_create_file(ctx->fd, system_pool, 0, FALSE);
 
12046
+       /*ctx->output = (storage->flags & SIEVE_STORAGE_FLAG_SAVE_CRLF) != 0 ?
 
12047
+               o_stream_create_crlf(default_pool, output) :
 
12048
+               o_stream_create_lf(default_pool, output);
 
12049
+       o_stream_unref(&output);*/
 
12050
+       ctx->output = output;
 
12051
+
 
12052
+       ctx->tmp_path = p_strdup(pool, path);
 
12053
+       ctx->failed = FALSE;
 
12054
+
 
12055
+       t_pop();        
 
12056
+       return ctx;
 
12057
+}
 
12058
+
 
12059
+int sieve_storage_save_continue(struct sieve_save_context *ctx)
 
12060
+{
 
12061
+       if (o_stream_send_istream(ctx->output, ctx->input) < 0) {
 
12062
+               sieve_storage_set_critical(ctx->storage,
 
12063
+                       "o_stream_send_istream(%s) failed: %m", ctx->tmp_path);
 
12064
+               ctx->failed = TRUE;
 
12065
+               return -1;
 
12066
+       }
 
12067
+       return 0;
 
12068
+}
 
12069
+
 
12070
+int sieve_storage_save_finish(struct sieve_save_context *ctx)
 
12071
+{
 
12072
+       int output_errno;
 
12073
+
 
12074
+       ctx->finished = TRUE;
 
12075
+       if (ctx->failed && ctx->fd == -1) {
 
12076
+               /* tmp file creation failed */
 
12077
+               return -1;
 
12078
+       }
 
12079
+
 
12080
+       t_push();
 
12081
+       output_errno = ctx->output->stream_errno;
 
12082
+       o_stream_destroy(&ctx->output);
 
12083
+
 
12084
+       if (fsync(ctx->fd) < 0) {
 
12085
+               sieve_storage_set_critical(ctx->storage,
 
12086
+                                         "fsync(%s) failed: %m", ctx->tmp_path);
 
12087
+               ctx->failed = TRUE;
 
12088
+       }
 
12089
+       if (close(ctx->fd) < 0) {
 
12090
+               sieve_storage_set_critical(ctx->storage,
 
12091
+                                         "close(%s) failed: %m", ctx->tmp_path);
 
12092
+               ctx->failed = TRUE;
 
12093
+       }
 
12094
+       ctx->fd = -1;
 
12095
+
 
12096
+       if (ctx->failed) {
 
12097
+               /* delete the tmp file */
 
12098
+               if (unlink(ctx->tmp_path) < 0 && errno != ENOENT) 
 
12099
+                       i_warning("Unlink(%s) failed: %m", ctx->tmp_path);
 
12100
+
 
12101
+               errno = output_errno;
 
12102
+               if (ENOSPACE(errno)) {
 
12103
+                       sieve_storage_set_error(ctx->storage,
 
12104
+                                              "Not enough disk space");
 
12105
+               } else if (errno != 0) {
 
12106
+                       sieve_storage_set_critical(ctx->storage,
 
12107
+                               "write(%s) failed: %m", ctx->tmp_path);
 
12108
+               }
 
12109
+
 
12110
+               t_pop();
 
12111
+               return -1;
 
12112
+       }
 
12113
+       t_pop();
 
12114
+
 
12115
+       return 0;
 
12116
+}
 
12117
+
 
12118
+static void sieve_storage_save_destroy(struct sieve_save_context *ctx)
 
12119
+{
 
12120
+       if (ctx->scriptobject != NULL)
 
12121
+               sieve_script_unref(&(ctx->scriptobject));
 
12122
+
 
12123
+       pool_unref(ctx->pool);
 
12124
+}
 
12125
+
 
12126
+struct sieve_script *sieve_storage_save_get_tempscript
 
12127
+       (struct sieve_save_context *ctx)
 
12128
+{
 
12129
+       if (ctx->failed) 
 
12130
+               return NULL;
 
12131
+
 
12132
+       ctx->scriptobject = sieve_script_init_from_file(ctx->storage, ctx->scriptname,
 
12133
+       ctx->tmp_path, NULL);   
 
12134
+
 
12135
+       return ctx->scriptobject;
 
12136
+}
 
12137
+
 
12138
+int sieve_storage_save_commit(struct sieve_save_context *ctx)
 
12139
+{
 
12140
+       const char *dest_path;
 
12141
+       bool failed = FALSE;
 
12142
+
 
12143
+       i_assert(ctx->output == NULL);
 
12144
+       i_assert(ctx->finished);
 
12145
+
 
12146
+       t_push();
 
12147
+
 
12148
+       dest_path = t_strconcat(ctx->storage->dir, "/", ctx->scriptname, ".sieve", NULL);
 
12149
+
 
12150
+       failed = !sieve_script_move(ctx, dest_path);
 
12151
+       
 
12152
+       t_pop();
 
12153
+
 
12154
+       sieve_storage_save_destroy(ctx);
 
12155
+
 
12156
+       return !failed;
 
12157
+}
 
12158
+
 
12159
+void sieve_storage_save_abort(struct sieve_save_context *ctx)
 
12160
+{
 
12161
+       ctx->failed = TRUE;
 
12162
+
 
12163
+       if (!ctx->finished) 
 
12164
+               (void)sieve_storage_save_finish(ctx);
 
12165
+       else
 
12166
+               (void)unlink(ctx->tmp_path);
 
12167
+
 
12168
+       i_assert(ctx->output == NULL);
 
12169
+
 
12170
+       sieve_storage_save_destroy(ctx);
 
12171
+}
 
12172
diff -r 894f003d9f5f src/lib-sievestorage/sieve-save.h
 
12173
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
12174
+++ b/src/lib-sievestorage/sieve-save.h Sun May 04 16:00:59 2008 +0200
 
12175
@@ -0,0 +1,24 @@
 
12176
+#ifndef __SIEVE_SAVE_H
 
12177
+#define __SIEVE_SAVE_H
 
12178
+
 
12179
+#include "sieve-storage.h"
 
12180
+
 
12181
+struct sieve_save_context;
 
12182
+
 
12183
+struct sieve_save_context *
 
12184
+sieve_storage_save_init(struct sieve_storage *storage,
 
12185
+       const char *scriptname, struct istream *input);
 
12186
+
 
12187
+int sieve_storage_save_continue(struct sieve_save_context *ctx);
 
12188
+
 
12189
+int sieve_storage_save_finish(struct sieve_save_context *ctx);
 
12190
+
 
12191
+struct sieve_script *sieve_storage_save_get_tempscript
 
12192
+  (struct sieve_save_context *ctx);
 
12193
+
 
12194
+void sieve_storage_save_abort(struct sieve_save_context *ctx);
 
12195
+
 
12196
+int sieve_storage_save_commit(struct sieve_save_context *ctx);
 
12197
+
 
12198
+#endif
 
12199
+
 
12200
diff -r 894f003d9f5f src/lib-sievestorage/sieve-script.c
 
12201
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
12202
+++ b/src/lib-sievestorage/sieve-script.c       Sun May 04 16:00:59 2008 +0200
 
12203
@@ -0,0 +1,634 @@
 
12204
+#include "lib.h"
 
12205
+#include "mempool.h"
 
12206
+#include "hostpid.h"
 
12207
+#include "ioloop.h"
 
12208
+#include "istream.h"
 
12209
+#include "file-copy.h"
 
12210
+
 
12211
+#include "sieve-storage.h"
 
12212
+#include "sieve-storage-private.h"
 
12213
+#include "sieve-script.h"
 
12214
+
 
12215
+#include <stdio.h>
 
12216
+#include <stdlib.h>
 
12217
+#include <unistd.h>
 
12218
+#include <sys/stat.h>
 
12219
+#include <ctype.h>
 
12220
+#include <time.h>
 
12221
+#include <fcntl.h>
 
12222
+
 
12223
+struct sieve_script *sieve_script_init_from_file
 
12224
+  (struct sieve_storage *storage, const char *scriptname, 
 
12225
+       const char *filename, bool *exists)
 
12226
+{
 
12227
+       int ret;
 
12228
+       struct stat st;
 
12229
+       pool_t pool;
 
12230
+       struct sieve_script *script = NULL;     
 
12231
+
 
12232
+       /* Prevent initializing the active script link as a script when it
 
12233
+     * resides in the sieve storage directory.
 
12234
+        */
 
12235
+       if ( *(storage->link_path) == '\0' ) {
 
12236
+               const char *fname;
 
12237
+
 
12238
+               fname = strrchr(filename, '/');
 
12239
+               if ( fname == NULL )
 
12240
+                       fname = filename;
 
12241
+               else
 
12242
+                       fname++;
 
12243
+
 
12244
+               if ( strcmp(fname, storage->active_fname) == 0 ) {
 
12245
+                       if ( exists != NULL )
 
12246
+                               *exists = FALSE;
 
12247
+                       return NULL;
 
12248
+               }
 
12249
+       }
 
12250
+
 
12251
+       /* Perform existance check if required */
 
12252
+       if (exists != NULL) {
 
12253
+               if (*exists) {
 
12254
+                       *exists = FALSE;
 
12255
+                       ret = stat(filename, &st);
 
12256
+                       
 
12257
+                       if ( ret < 0 ) {
 
12258
+                               if ( errno == ENOENT ) {
 
12259
+                                       return NULL;
 
12260
+                               }
 
12261
+
 
12262
+                               sieve_storage_set_critical
 
12263
+                                 (storage,      
 
12264
+                                       "Performing stat() on sieve file '%s' failed: %m", filename);
 
12265
+                               return NULL;
 
12266
+                       }
 
12267
+
 
12268
+                       if ( !S_ISREG(st.st_mode) ) {
 
12269
+                               sieve_storage_set_critical
 
12270
+                                 (storage, "Sieve file '%s' is not a regular file.", filename);
 
12271
+                               return NULL;
 
12272
+                       }
 
12273
+       
 
12274
+                       /* Script found */
 
12275
+                       *exists = TRUE;
 
12276
+               }
 
12277
+       }
 
12278
+
 
12279
+       pool = pool_alloconly_create("sieve_script", 4096);     
 
12280
+       script = p_new(pool, struct sieve_script, 1);
 
12281
+       script->pool = pool;
 
12282
+       script->refcount = 1;
 
12283
+       script->name = p_strdup(pool, scriptname);
 
12284
+       script->storage = storage;
 
12285
+       script->size = st.st_size;
 
12286
+
 
12287
+       script->filename = p_strdup(pool, filename);
 
12288
+       script->istream = NULL; 
 
12289
+
 
12290
+       return script;
 
12291
+}
 
12292
+
 
12293
+struct sieve_script *sieve_script_init
 
12294
+       (struct sieve_storage *storage, const char *scriptname, bool *exists)
 
12295
+{      
 
12296
+       struct sieve_script *script;
 
12297
+       const char *filename;
 
12298
+
 
12299
+       t_push();
 
12300
+
 
12301
+       filename = t_strconcat
 
12302
+         ( storage->dir, "/", scriptname, ".sieve", NULL );
 
12303
+
 
12304
+       script = sieve_script_init_from_file(storage, scriptname, filename, exists);
 
12305
+
 
12306
+       t_pop();
 
12307
+
 
12308
+       return script;
 
12309
+}
 
12310
+
 
12311
+void sieve_script_ref(struct sieve_script *script)
 
12312
+{
 
12313
+       script->refcount++;
 
12314
+}
 
12315
+
 
12316
+void sieve_script_unref(struct sieve_script **script)
 
12317
+{
 
12318
+       i_assert((*script)->refcount > 0);
 
12319
+       
 
12320
+       if (--(*script)->refcount != 0)
 
12321
+               return;
 
12322
+
 
12323
+       if ((*script)->istream != NULL ) 
 
12324
+               i_stream_unref(&(*script)->istream);
 
12325
+
 
12326
+       pool_unref((*script)->pool);
 
12327
+       
 
12328
+       *script = NULL;
 
12329
+}
 
12330
+
 
12331
+const char *sieve_script_name(struct sieve_script *script)
 
12332
+{
 
12333
+       return script->name;
 
12334
+}
 
12335
+
 
12336
+/* sieve_script_filename(): 
 
12337
+ * Returns the filename of the script. If the implemented storage
 
12338
+ * does not actually store scripts as a file a copy must be put
 
12339
+ * somewhere in /tmp or so. Don't use this function if you can
 
12340
+ * also work with a stream.
 
12341
+ */
 
12342
+const char *sieve_script_filename(struct sieve_script *script)
 
12343
+{
 
12344
+       return script->filename;
 
12345
+}
 
12346
+
 
12347
+static int
 
12348
+sieve_storage_open_fd(struct sieve_storage *storage, const char *path, int *fd)
 
12349
+{
 
12350
+       *fd = open(path, O_RDONLY);
 
12351
+       if (*fd != -1)
 
12352
+               return 1;
 
12353
+       if (errno == ENOENT)
 
12354
+               return 0;
 
12355
+
 
12356
+       sieve_storage_set_critical(storage,
 
12357
+                                  "open(%s) failed: %m", path);
 
12358
+       return -1;
 
12359
+}
 
12360
+
 
12361
+int sieve_script_get_size(struct sieve_script *script, uoff_t *size)
 
12362
+{
 
12363
+       int ret = 0;
 
12364
+
 
12365
+       *size = 0;
 
12366
+
 
12367
+       if (script->size == 0) {
 
12368
+               struct stat st;
 
12369
+
 
12370
+               ret = stat(script->filename, &st);
 
12371
+
 
12372
+               if ( ret < 0 ) {
 
12373
+                       if ( errno == ENOENT ) {
 
12374
+                               return 0;
 
12375
+                       }
 
12376
+                       
 
12377
+                       sieve_storage_set_critical
 
12378
+                         (script->storage,
 
12379
+                          "Performing stat() on sieve file '%s' failed: %m", script->filename);
 
12380
+                       
 
12381
+                       return -1;
 
12382
+               }
 
12383
+
 
12384
+               script->size = st.st_size;
 
12385
+       } 
 
12386
+       
 
12387
+       *size = script->size;
 
12388
+       
 
12389
+       return 1;
 
12390
+}
 
12391
+
 
12392
+struct istream *
 
12393
+sieve_script_open(struct sieve_script *script, bool *deleted_r)
 
12394
+{
 
12395
+       const struct stat *statbuf;
 
12396
+       int ret = 0, fd = -1;
 
12397
+
 
12398
+       if ( deleted_r != NULL )
 
12399
+               *deleted_r = FALSE;
 
12400
+
 
12401
+       if (script->istream == NULL) {
 
12402
+               if ( (ret=sieve_storage_open_fd
 
12403
+                   (script->storage, script->filename, &fd)) < 0) 
 
12404
+                       return NULL;
 
12405
+
 
12406
+               if (ret == 0) {
 
12407
+                       if ( deleted_r != NULL )
 
12408
+                               *deleted_r = TRUE;
 
12409
+                       return NULL;
 
12410
+               }
 
12411
+
 
12412
+               script->istream = 
 
12413
+                 i_stream_create_file(fd, default_pool,
 
12414
+                                      SIEVE_READ_BLOCK_SIZE, TRUE);
 
12415
+
 
12416
+               if ( script->istream != NULL ) {
 
12417
+                       statbuf = i_stream_stat(script->istream, 0);
 
12418
+                       script->size = statbuf->st_size;
 
12419
+               }       
 
12420
+       }
 
12421
+
 
12422
+       return script->istream;
 
12423
+}
 
12424
+
 
12425
+const char *sieve_storage_file_get_scriptname
 
12426
+       (const struct sieve_storage *storage __attr_unused__, const char *filename)
 
12427
+{
 
12428
+       const char *ext;
 
12429
+
 
12430
+       ext = strrchr(filename, '.');
 
12431
+
 
12432
+       if ( ext == NULL || ext == filename || strncmp(ext,".sieve",6) != 0 ) 
 
12433
+               return NULL;
 
12434
+       
 
12435
+       return t_strdup_until(filename, ext);
 
12436
+}
 
12437
+
 
12438
+static const char *sieve_storage_read_active_link
 
12439
+       (struct sieve_storage *storage, bool *not_link)
 
12440
+{
 
12441
+  char linkbuf[PATH_MAX];
 
12442
+  int ret;
 
12443
+
 
12444
+       if ( not_link != NULL )
 
12445
+               *not_link = FALSE;
 
12446
+
 
12447
+       ret = readlink(storage->active_path, linkbuf, sizeof(linkbuf));
 
12448
+
 
12449
+       if ( ret < 0 ) {
 
12450
+               if (errno == EINVAL) {
 
12451
+                       /* Our symlink is no symlink. Report 'no active script'.
 
12452
+                        * Activating a script will automatically resolve this, so
 
12453
+                        * there is no need to panic on this one.
 
12454
+                        */
 
12455
+                       i_warning
 
12456
+                         ("Active sieve script symlink %s is no symlink.",
 
12457
+                          storage->active_path);
 
12458
+                       if ( not_link != NULL )
 
12459
+                               *not_link = TRUE;
 
12460
+                       return "";
 
12461
+               }
 
12462
+
 
12463
+               if (errno != ENOENT ) {
 
12464
+                       /* We do need to panic otherwise */
 
12465
+                       sieve_storage_set_critical
 
12466
+                         (storage,
 
12467
+                               "Performing readlink() on active sieve symlink '%s' failed: %m", 
 
12468
+                                       storage->active_path);
 
12469
+                       return NULL;
 
12470
+               }
 
12471
+
 
12472
+               return "";
 
12473
+       }
 
12474
+
 
12475
+       /* ret is now assured to be valid, i.e. > 0 */
 
12476
+       return t_strndup(linkbuf, ret);
 
12477
+}
 
12478
+
 
12479
+static const char *sieve_storage_parse_link
 
12480
+       (struct sieve_storage *storage, const char *link)
 
12481
+{
 
12482
+       const char *fname, *scriptname, *scriptpath;
 
12483
+
 
12484
+       /* Split link into path and filename */
 
12485
+       fname = strrchr(link, '/');
 
12486
+       if ( fname != NULL ) {
 
12487
+               scriptpath = t_strdup_until(link, fname+1);
 
12488
+               fname++;
 
12489
+       } else {
 
12490
+               scriptpath = "";
 
12491
+               fname = link;
 
12492
+       }
 
12493
+
 
12494
+       /* Check the script name */
 
12495
+       scriptname = sieve_storage_file_get_scriptname(storage, fname);
 
12496
+
 
12497
+       /* Warn if link is deemed to be invalid */
 
12498
+       if ( scriptname == NULL ) {
 
12499
+               i_warning
 
12500
+                       ("Active sieve script symlink %s is broken: "
 
12501
+                               "invalid scriptname (points to %s).",
 
12502
+                               storage->active_path, link);
 
12503
+               return NULL;
 
12504
+       }
 
12505
+
 
12506
+       /* Check whether the path is any good */
 
12507
+       if ( strcmp(scriptpath, storage->link_path) != 0 &&
 
12508
+               strcmp(scriptpath, storage->dir) != 0 ) {
 
12509
+               i_warning
 
12510
+                       ("Active sieve script symlink %s is broken: "
 
12511
+                               "invalid/unknown path to storage (points to %s).",
 
12512
+                               storage->active_path, link);
 
12513
+               return NULL; 
 
12514
+       }
 
12515
+
 
12516
+       return scriptname;
 
12517
+}
 
12518
+
 
12519
+const char *sieve_storage_get_active_scriptname
 
12520
+       (struct sieve_storage *storage)
 
12521
+{
 
12522
+       const char *link, *scriptname;
 
12523
+
 
12524
+       /* Read the active link */
 
12525
+       link = sieve_storage_read_active_link(storage, NULL);
 
12526
+
 
12527
+       if ( link == NULL || *link == '\0' ) 
 
12528
+               return link;
 
12529
+
 
12530
+       /* Parse the link */
 
12531
+       scriptname = sieve_storage_parse_link(storage, link);
 
12532
+
 
12533
+       if (scriptname == NULL) {
 
12534
+               /* Obviously someone has been playing with our symlink,
 
12535
+                * ignore this situation and report 'no active script'.
 
12536
+                * Activation should fix this situation.
 
12537
+                */
 
12538
+               return "";
 
12539
+       }
 
12540
+
 
12541
+       return scriptname;
 
12542
+}
 
12543
+
 
12544
+struct sieve_script *
 
12545
+  sieve_storage_get_active_script(struct sieve_storage *storage, bool *no_active)
 
12546
+{
 
12547
+       bool exists, no_link;
 
12548
+       struct sieve_script *script;
 
12549
+       const char *scriptname, *link;
 
12550
+
 
12551
+       *no_active = FALSE;
 
12552
+
 
12553
+       /* Read the active link */
 
12554
+       link = sieve_storage_read_active_link(storage, &no_link);
 
12555
+       
 
12556
+       if ( link == NULL )
 
12557
+               /* Error */
 
12558
+               return NULL;
 
12559
+
 
12560
+       if ( *link == '\0' )
 
12561
+       {
 
12562
+               if (no_link) {
 
12563
+                       /* Try to open the active_path as a regular file */
 
12564
+                       return sieve_script_init_from_file
 
12565
+                               (storage, ".dovecot", storage->active_path, NULL);
 
12566
+               }
 
12567
+
 
12568
+               *no_active = TRUE;
 
12569
+               return NULL;
 
12570
+       }
 
12571
+
 
12572
+       /* Parse the link */
 
12573
+       scriptname = sieve_storage_parse_link(storage, link);
 
12574
+
 
12575
+       if (scriptname == NULL) {
 
12576
+               /* Obviously someone has been playing with our symlink,
 
12577
+                * ignore this situation and report 'no active script'.
 
12578
+                */
 
12579
+               *no_active = TRUE;
 
12580
+               return NULL;
 
12581
+       }
 
12582
+       
 
12583
+       exists = TRUE;
 
12584
+       script = sieve_script_init(storage, scriptname, &exists);       
 
12585
+
 
12586
+       if ( !exists ) {
 
12587
+               i_warning
 
12588
+                 ("Active sieve script symlink %s "
 
12589
+                  "points to non-existent script (points to %s).",
 
12590
+                  storage->active_path, link);
 
12591
+       }
 
12592
+       
 
12593
+       *no_active = !exists;
 
12594
+       return script;
 
12595
+}
 
12596
+
 
12597
+int sieve_script_is_active(struct sieve_script *script)
 
12598
+{
 
12599
+       const char *aname;
 
12600
+
 
12601
+       t_push();
 
12602
+       
 
12603
+       aname = sieve_storage_get_active_scriptname(script->storage);
 
12604
+       
 
12605
+       if (aname == NULL) {
 
12606
+               /* Critical error */
 
12607
+               t_pop();
 
12608
+               return -1;
 
12609
+       }
 
12610
+
 
12611
+       /* Is the requested script active? */
 
12612
+       if ( strcmp(script->name, aname) == 0 ) {
 
12613
+               t_pop();
 
12614
+               return 1;
 
12615
+       }
 
12616
+
 
12617
+       t_pop();
 
12618
+       return 0;
 
12619
+}
 
12620
+
 
12621
+int sieve_script_delete(struct sieve_script **script) 
 
12622
+{
 
12623
+       struct sieve_storage *storage = (*script)->storage;
 
12624
+       int ret = 0;
 
12625
+
 
12626
+
 
12627
+       /* Is the requested script active? */
 
12628
+       if ( sieve_script_is_active(*script) ) {
 
12629
+               sieve_storage_set_error(storage, "Cannot delete the active sieve script.");
 
12630
+               ret = -1;
 
12631
+       } else {
 
12632
+               ret = unlink((*script)->filename);
 
12633
+
 
12634
+               if ( ret < 0 ) {
 
12635
+                       if ( errno == ENOENT ) 
 
12636
+                               sieve_storage_set_error(storage, "Sieve script does not exist.");
 
12637
+                       else
 
12638
+                               sieve_storage_set_critical(
 
12639
+                                       storage, "Performing unlink() failed on sieve file '%s': %m", 
 
12640
+                                       (*script)->filename);
 
12641
+               }       
 
12642
+       }
 
12643
+
 
12644
+       /* Always deinitialize the script object */
 
12645
+       sieve_script_unref(script);
 
12646
+
 
12647
+       return ret;     
 
12648
+}
 
12649
+
 
12650
+static bool sieve_storage_rescue_regular_file(struct sieve_storage *storage)
 
12651
+{
 
12652
+       struct stat st;
 
12653
+       
 
12654
+       /* Stat the file */
 
12655
+       if ( lstat(storage->active_path, &st) != 0 ) {
 
12656
+               if ( errno != ENOENT ) {
 
12657
+                       sieve_storage_set_critical(storage, 
 
12658
+                               "Failed to stat active sieve script symlink (%s): %m.", 
 
12659
+                               storage->active_path); 
 
12660
+                       return FALSE;   
 
12661
+               } 
 
12662
+               return TRUE;
 
12663
+       }
 
12664
+
 
12665
+       if ( S_ISLNK( st.st_mode ) ) {
 
12666
+               if ( getenv("DEBUG") != NULL )
 
12667
+               i_info( "sieve-storage: nothing to rescue %s.", storage->active_path);
 
12668
+       return TRUE; /* Nothing to rescue */
 
12669
+       }
 
12670
+
 
12671
+       /* Only regular files can be rescued */
 
12672
+       if ( S_ISREG( st.st_mode ) ) {
 
12673
+               const char *dstpath;
 
12674
+
 
12675
+               t_push();
 
12676
+
 
12677
+               dstpath = t_strconcat
 
12678
+                       ( storage->dir, "/dovecot.orig.sieve", NULL );
 
12679
+               if ( file_copy(storage->active_path, dstpath, 1) < 1 ) {
 
12680
+                       sieve_storage_set_critical(storage, 
 
12681
+                               "Active sieve script file '%s' is a regular file and copying it to the "
 
12682
+                               "script storage as '%s' failed. This needs to be fixed manually.",
 
12683
+                               storage->active_path, dstpath);
 
12684
+                       t_pop();
 
12685
+                       return FALSE;   
 
12686
+               } else {
 
12687
+                       i_info("Moved active sieve script file '%s' to script storage as '%s'.",
 
12688
+                               storage->active_path, dstpath); 
 
12689
+                       t_pop();
 
12690
+                       return TRUE;
 
12691
+       }
 
12692
+               t_pop();
 
12693
+       }
 
12694
+
 
12695
+       sieve_storage_set_critical( storage,
 
12696
+               "Active sieve script file '%s' is no symlink nor a regular file. "
 
12697
+               "This needs to be fixed manually.", storage->active_path );
 
12698
+       return FALSE;   
 
12699
+}
 
12700
+
 
12701
+int sieve_storage_deactivate(struct sieve_storage *storage)
 
12702
+{
 
12703
+       int ret;
 
12704
+
 
12705
+       if ( !sieve_storage_rescue_regular_file(storage) ) 
 
12706
+               return -1;
 
12707
+
 
12708
+       /* Delete the symlink, so no script is active */
 
12709
+       ret = unlink(storage->active_path);
 
12710
+
 
12711
+       if ( ret < 0 ) {
 
12712
+               if ( errno != ENOENT ) {
 
12713
+                       sieve_storage_set_error(storage, "sieve_storage_deactivate(): "
 
12714
+                               "error on unlink(%s): %m", storage->active_path);
 
12715
+                       return -1;
 
12716
+               } else 
 
12717
+                 return 0;
 
12718
+       } 
 
12719
+
 
12720
+       return 1;
 
12721
+}
 
12722
+
 
12723
+int
 
12724
+sieve_script_activate(struct sieve_script *script)
 
12725
+{
 
12726
+       struct stat st;
 
12727
+       const char *active_path_new, *script_path;
 
12728
+       struct timeval *tv, tv_now;
 
12729
+       const char *aname;
 
12730
+       int activated = 0;
 
12731
+       int ret;
 
12732
+
 
12733
+       t_push();       
 
12734
+
 
12735
+       /* Find out whether there is an active script, but recreate
 
12736
+        * the symlink either way. This way, any possible error in the symlink
 
12737
+        * resolves automatically. This step is only necessary to provide a
 
12738
+        * proper return value indicating whether the script was already active.
 
12739
+        */
 
12740
+       aname = sieve_storage_get_active_scriptname(script->storage);
 
12741
+
 
12742
+       /* Is the requested script already active? */
 
12743
+       if ( aname == NULL || strcmp(script->name, aname) != 0 ) 
 
12744
+               activated = 1; 
 
12745
+
 
12746
+       /* Check the scriptfile we are trying to activate */
 
12747
+       if ( lstat(script->filename, &st) != 0 ) {
 
12748
+               sieve_storage_set_critical(script->storage, 
 
12749
+                 "Stat on sieve script %s failed, but it is to be activated: %m.", script->name);
 
12750
+               t_pop();
 
12751
+               return -1;
 
12752
+       }
 
12753
+
 
12754
+       /* Rescue a possible .dovecot.sieve regular file remaining from old 
 
12755
+        * installations.
 
12756
+        */
 
12757
+       if ( !sieve_storage_rescue_regular_file(script->storage) ) {
 
12758
+               /* Rescue failed, manual intervention is necessary */
 
12759
+               t_pop();
 
12760
+               return -1;
 
12761
+       }
 
12762
+
 
12763
+       /* Just try to create the symlink first */
 
12764
+       script_path = t_strconcat
 
12765
+         ( script->storage->link_path, script->name, ".sieve", NULL );
 
12766
+               
 
12767
+       ret = symlink(script_path, script->storage->active_path);
 
12768
+
 
12769
+       if ( ret < 0 ) {
 
12770
+               if ( errno == EEXIST ) {
 
12771
+                       /* The symlink already exists, try to replace it */
 
12772
+                       tv = &ioloop_timeval;
 
12773
+
 
12774
+                       for (;;) {      
 
12775
+                               /* First the new symlink is created with a different filename */
 
12776
+                               active_path_new = t_strdup_printf
 
12777
+                                       ("%s-new.%s.P%sM%s.%s.sieve",
 
12778
+                                               script->storage->active_path,
 
12779
+                                               dec2str(tv->tv_sec), my_pid,
 
12780
+                                               dec2str(tv->tv_usec), my_hostname);
 
12781
+
 
12782
+                               ret = symlink(script_path, active_path_new);
 
12783
+               
 
12784
+                               if ( ret < 0 ) {
 
12785
+                                       /* If link exists we try again later */
 
12786
+                                       if ( errno == EEXIST ) {
 
12787
+                                               /* Wait and try again - very unlikely */
 
12788
+                                               sleep(2);
 
12789
+                                               tv = &tv_now;
 
12790
+                                               if (gettimeofday(&tv_now, NULL) < 0)
 
12791
+                                                       i_fatal("gettimeofday(): %m");
 
12792
+                                               continue;
 
12793
+                                       }
 
12794
+
 
12795
+                                       /* Other error, critical */
 
12796
+                                       sieve_storage_set_critical
 
12797
+                                         (script->storage, 
 
12798
+                                          "Creating symlink() %s to %s failed: %m", 
 
12799
+                                          active_path_new, script_path);
 
12800
+                                       t_pop();
 
12801
+                                       return -1;
 
12802
+                               }
 
12803
+       
 
12804
+                               /* Link created */
 
12805
+                               break;
 
12806
+                       }
 
12807
+
 
12808
+                       /* Replace the existing link and thus activating the new script */
 
12809
+                       ret = rename(active_path_new, script->storage->active_path);
 
12810
+
 
12811
+                       if ( ret < 0 ) {
 
12812
+                               /* Failed; created symlink must be deleted */
 
12813
+                               (void)unlink(active_path_new);
 
12814
+                               sieve_storage_set_critical
 
12815
+                                 (script->storage,
 
12816
+                                  "Performing rename() %s to %s failed: %m", 
 
12817
+                                  active_path_new, script->storage->active_path);
 
12818
+                               t_pop();
 
12819
+                               return -1;
 
12820
+                       }       
 
12821
+               } else {
 
12822
+                       /* Other error, critical */
 
12823
+                       sieve_storage_set_critical
 
12824
+                               (script->storage,
 
12825
+                                       "Creating symlink() %s to %s failed: %m",
 
12826
+                                       script->storage->active_path, script_path);
 
12827
+                       t_pop();
 
12828
+                       return -1;
 
12829
+               }
 
12830
+       }
 
12831
+
 
12832
+       t_pop();
 
12833
+       return activated;
 
12834
+}
 
12835
+
 
12836
+
 
12837
+
 
12838
diff -r 894f003d9f5f src/lib-sievestorage/sieve-script.h
 
12839
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
12840
+++ b/src/lib-sievestorage/sieve-script.h       Sun May 04 16:00:59 2008 +0200
 
12841
@@ -0,0 +1,49 @@
 
12842
+#ifndef __SIEVE_FILE_H
 
12843
+#define __SIEVE_FILE_H
 
12844
+
 
12845
+#include "sieve-storage.h"
 
12846
+
 
12847
+struct sieve_script;
 
12848
+
 
12849
+struct sieve_script *sieve_script_init
 
12850
+  (struct sieve_storage *storage, const char *scriptname, bool *exists);
 
12851
+
 
12852
+void sieve_script_ref(struct sieve_script *script);
 
12853
+
 
12854
+void sieve_script_unref(struct sieve_script **script);
 
12855
+
 
12856
+const char *sieve_script_name(struct sieve_script *script);
 
12857
+
 
12858
+/* sieve_script_filename():
 
12859
+ * Returns the filename of the script. If the implemented storage
 
12860
+ * does not actually store scripts as a file it must temporarily be saved
 
12861
+ * somewhere in /tmp or so. Don't use this function if you can
 
12862
+ * also work with a stream. (currently not an issue)
 
12863
+ */
 
12864
+const char *sieve_script_filename(struct sieve_script *script);
 
12865
+
 
12866
+int sieve_script_get_size(struct sieve_script *script, uoff_t *size);
 
12867
+
 
12868
+struct istream *
 
12869
+sieve_script_open(struct sieve_script *script, bool *deleted_r);
 
12870
+
 
12871
+const char *sieve_storage_file_get_scriptname
 
12872
+  (const struct sieve_storage *storage, const char *filename);
 
12873
+
 
12874
+const char *
 
12875
+  sieve_storage_get_active_scriptname(struct sieve_storage *storage);
 
12876
+
 
12877
+struct sieve_script *
 
12878
+  sieve_storage_get_active_script(struct sieve_storage *storage, bool *no_active);
 
12879
+
 
12880
+int sieve_script_is_active(struct sieve_script *script);
 
12881
+
 
12882
+int sieve_script_delete(struct sieve_script **script);
 
12883
+
 
12884
+int sieve_storage_deactivate(struct sieve_storage *storage);
 
12885
+
 
12886
+int
 
12887
+sieve_script_activate(struct sieve_script *script);
 
12888
+
 
12889
+#endif
 
12890
+
 
12891
diff -r 894f003d9f5f src/lib-sievestorage/sieve-storage-private.h
 
12892
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
12893
+++ b/src/lib-sievestorage/sieve-storage-private.h      Sun May 04 16:00:59 2008 +0200
 
12894
@@ -0,0 +1,47 @@
 
12895
+#ifndef __SIEVE_STORAGE_PRIVATE_H
 
12896
+#define __SIEVE_STORAGE_PRIVATE_H
 
12897
+
 
12898
+#include "sieve-storage.h"
 
12899
+
 
12900
+enum sieve_storage_flags {
 
12901
+       /* Print debugging information while initializing the storage */
 
12902
+       SIEVE_STORAGE_FLAG_DEBUG     = 0x01,
 
12903
+       /* Use CRLF linefeeds when saving mails. */
 
12904
+       SIEVE_STORAGE_FLAG_SAVE_CRLF   = 0x02,
 
12905
+};
 
12906
+
 
12907
+#define SIEVE_READ_BLOCK_SIZE (1024*8)
 
12908
+
 
12909
+/* All methods returning int return either TRUE or FALSE. */
 
12910
+struct sieve_storage {
 
12911
+       pool_t pool;
 
12912
+       char *name;
 
12913
+       char *dir;
 
12914
+
 
12915
+       /* Private */   
 
12916
+       char *active_path;
 
12917
+       char *active_fname;
 
12918
+       char *link_path;
 
12919
+       char *error;
 
12920
+       char *user; /* name of user accessing the storage */
 
12921
+
 
12922
+       enum sieve_storage_flags flags;
 
12923
+};
 
12924
+
 
12925
+struct sieve_script {
 
12926
+       pool_t pool;
 
12927
+       int refcount;
 
12928
+
 
12929
+       struct sieve_storage *storage;
 
12930
+       const char *name;
 
12931
+       struct istream *istream;
 
12932
+       const char *filename;
 
12933
+       uoff_t size;
 
12934
+};
 
12935
+
 
12936
+struct sieve_script *sieve_script_init_from_file
 
12937
+       (struct sieve_storage *storage, const char *scriptname,
 
12938
+       const char *filename, bool *exists);
 
12939
+
 
12940
+#endif
 
12941
+
 
12942
diff -r 894f003d9f5f src/lib-sievestorage/sieve-storage.c
 
12943
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
12944
+++ b/src/lib-sievestorage/sieve-storage.c      Sun May 04 16:00:59 2008 +0200
 
12945
@@ -0,0 +1,402 @@
 
12946
+#include "lib.h"
 
12947
+#include "home-expand.h"
 
12948
+#include "ioloop.h"
 
12949
+#include "mkdir-parents.h"
 
12950
+#include "sieve-storage-private.h"
 
12951
+
 
12952
+#include <stdio.h>
 
12953
+#include <stdlib.h>
 
12954
+#include <unistd.h>
 
12955
+#include <sys/stat.h>
 
12956
+#include <ctype.h>
 
12957
+#include <time.h>
 
12958
+
 
12959
+#define SIEVE_SCRIPT_PATH "~/.dovecot.sieve"
 
12960
+
 
12961
+#define CREATE_MODE 0770 /* umask() should limit it more */
 
12962
+
 
12963
+#define CRITICAL_MSG \
 
12964
+  "Internal error occured. Refer to server log for more information."
 
12965
+#define CRITICAL_MSG_STAMP CRITICAL_MSG " [%Y-%m-%d %H:%M:%S]"
 
12966
+
 
12967
+static const char *sieve_get_active_script_path(void)
 
12968
+{
 
12969
+  const char *script_path, *home;
 
12970
+
 
12971
+  home = getenv("HOME");
 
12972
+
 
12973
+  /* userdb may specify Sieve path */
 
12974
+  script_path = getenv("SIEVE");
 
12975
+  if (script_path != NULL) {
 
12976
+       if (*script_path == '\0') {
 
12977
+               /* disabled */
 
12978
+               return NULL;
 
12979
+       }
 
12980
+
 
12981
+    if ( *script_path != '/' && *script_path != '~') {
 
12982
+      /* relative path. change to absolute. */
 
12983
+      script_path = t_strconcat(getenv("HOME"), "/",  
 
12984
+        script_path, NULL);
 
12985
+    }
 
12986
+  } else {
 
12987
+    if (home == NULL) {
 
12988
+      /* we must have a home directory */
 
12989
+      i_error("sieve-storage: userdb(%s) didn't return a home directory or "
 
12990
+        "sieve script location, can't find it",
 
12991
+        getenv("USER"));
 
12992
+      return NULL;
 
12993
+    }
 
12994
+
 
12995
+    script_path = SIEVE_SCRIPT_PATH;
 
12996
+  }
 
12997
+
 
12998
+  /* No need to check for existance here */
 
12999
+
 
13000
+  return script_path;
 
13001
+}
 
13002
+
 
13003
+/* Obtain the directory for script storage from the mail location
 
13004
+ */
 
13005
+static const char *sieve_storage_get_dir_from_mail(const char *data)
 
13006
+{
 
13007
+       bool debug = (getenv("DEBUG") != NULL);
 
13008
+       struct stat st;
 
13009
+       size_t len;
 
13010
+       const char *root_dir, *dir, *p, *d;
 
13011
+
 
13012
+       root_dir = dir = d = NULL;
 
13013
+
 
13014
+       if (debug)
 
13015
+               i_info("sieve-storage: using mail-data: %s", data);
 
13016
+
 
13017
+       /* check if we're in the form of mailformat:data
 
13018
+          (eg. maildir:Maildir) */
 
13019
+       p = data;
 
13020
+       while (i_isalnum(*p)) p++;
 
13021
+       
 
13022
+       if (*p == ':') {
 
13023
+               d = p+1;
 
13024
+       } else {
 
13025
+               d = data;
 
13026
+       }
 
13027
+
 
13028
+       if (d == NULL || *d == '\0') {
 
13029
+               /* Ok, this is bad. Check whether we might be chrooted, bail out otherwise */
 
13030
+               if (access("/sieve", R_OK|W_OK|X_OK) == 0)
 
13031
+                       root_dir = "/";
 
13032
+               else {
 
13033
+                       i_error("sieve-storage: sieve storage directory not given "
 
13034
+                               "and mail root provides no alternative.");
 
13035
+            return NULL;
 
13036
+               }
 
13037
+       } else {
 
13038
+               /* <scriptdir> */
 
13039
+               p = strchr(d, ':');
 
13040
+               if (p == NULL)
 
13041
+                       /* No additional parameters */
 
13042
+                       root_dir = d;
 
13043
+               else {
 
13044
+                       dir = t_strdup_until(d, p);
 
13045
 
13046
+                       do {
 
13047
+                               p++;
 
13048
+                               /* Use control dir as script dir if specified */
 
13049
+                               if (strncmp(p, "CONTROL=", 8) == 0)
 
13050
+                                       root_dir = t_strcut(p+8, ':');
 
13051
+                               p = strchr(p, ':');
 
13052
+                       } while (p != NULL);
 
13053
+                       
 
13054
+                       if ( root_dir == NULL || *root_dir == '\0' )
 
13055
+                               root_dir = dir;
 
13056
+               }
 
13057
+       }
 
13058
+
 
13059
+       /* Not found */
 
13060
+       if ( root_dir == NULL || *root_dir == '\0' ) {
 
13061
+               if (debug)
 
13062
+            i_info("sieve-storage: couldn't find root dir from mail-data.");
 
13063
+        return NULL;
 
13064
+    }
 
13065
+
 
13066
+       /* Strip trailing '/' */
 
13067
+    len = strlen(root_dir);
 
13068
+    if (root_dir[len-1] == '/')
 
13069
+        root_dir = t_strndup(root_dir, len-1);
 
13070
+
 
13071
+       /* Superior mail directory must exist; it is never auto-created by the 
 
13072
+        * sieve-storage.
 
13073
+        */
 
13074
+       if (stat(root_dir, &st) < 0 ) {
 
13075
+               if ( errno != ENOENT ) {
 
13076
+                       i_error("sieve-storage: stat(%s) failed: %m", root_dir);
 
13077
+                       return NULL;
 
13078
+               } else {
 
13079
+                       i_error("sieve-storage: root directory specified by "
 
13080
+                               "mail data does not exist: %s", root_dir);
 
13081
+                       return NULL;
 
13082
+               }
 
13083
+       } 
 
13084
+
 
13085
+       /* Never store scripts directly in the root of the mail or mail:CONTROl directory.
 
13086
+        */
 
13087
+       root_dir = t_strconcat( root_dir, "/sieve", NULL );
 
13088
+
 
13089
+       return root_dir;
 
13090
+}
 
13091
+
 
13092
+static const char *sieve_storage_get_relative_link_path
 
13093
+       (const char *active_path, const char *storage_dir) 
 
13094
+{
 
13095
+       const char *link_path, *p;
 
13096
+       size_t pathlen;
 
13097
+       
 
13098
+       /* Determine to what extent the sieve storage and active script 
 
13099
+        * paths match up. This enables the managed symlink to be short and the 
 
13100
+        * sieve storages can be moved around without trouble (if the active 
 
13101
+        * script path is common to the script storage).
 
13102
+        */             
 
13103
+       p = strrchr(active_path, '/');
 
13104
+       if ( p == NULL ) {
 
13105
+               link_path = storage_dir;
 
13106
+       } else { 
 
13107
+               pathlen = p - active_path;
 
13108
+
 
13109
+               if ( strncmp( active_path, storage_dir, pathlen ) == 0 &&
 
13110
+                       (storage_dir[pathlen] == '/' || storage_dir[pathlen] == '\0') ) 
 
13111
+               {
 
13112
+                       if ( storage_dir[pathlen] == '\0' ) 
 
13113
+                               link_path = ""; 
 
13114
+                       else 
 
13115
+                               link_path = storage_dir + pathlen + 1;
 
13116
+               } else 
 
13117
+                       link_path = storage_dir;
 
13118
+       }
 
13119
+
 
13120
+       /* Add trailing '/' when link path is not empty 
 
13121
+        */
 
13122
+       pathlen = strlen(link_path);
 
13123
+    if ( pathlen != 0 && link_path[pathlen-1] != '/')
 
13124
+        return t_strconcat(link_path, "/", NULL);
 
13125
+
 
13126
+       return t_strdup(link_path);
 
13127
+}
 
13128
+
 
13129
+struct sieve_storage *sieve_storage_create_from_mail(const char *data, const char *user)
 
13130
+{
 
13131
+       struct sieve_storage *storage;
 
13132
+       const char *storage_dir;
 
13133
+
 
13134
+       t_push();
 
13135
+
 
13136
+       storage_dir = sieve_storage_get_dir_from_mail(data);
 
13137
+       if (storage_dir == NULL) {
 
13138
+               if (getenv("DEBUG") != NULL)
 
13139
+                       i_info("sieve-storage: failed to obtain storage directory from mail-data.");
 
13140
+               t_pop();
 
13141
+               return NULL;
 
13142
+       } 
 
13143
+
 
13144
+       storage = sieve_storage_create(storage_dir, user);
 
13145
+
 
13146
+       t_pop();
 
13147
+
 
13148
+       return storage;
 
13149
+}
 
13150
+
 
13151
+struct sieve_storage *sieve_storage_create(const char *data, const char *user)
 
13152
+{
 
13153
+       bool debug = (getenv("DEBUG") != NULL);
 
13154
+       pool_t pool;
 
13155
+       struct sieve_storage *storage;
 
13156
+       const char *home, *tmp_dir, *link_path, *path;
 
13157
+       const char *active_path, *active_fname, *storage_dir;
 
13158
+
 
13159
+       t_push();
 
13160
+
 
13161
+       /* Find out where the active script is stored (e.g. ~/.dovecot.sieve) */
 
13162
+
 
13163
+       active_path = sieve_get_active_script_path();
 
13164
+       if (active_path == NULL) {
 
13165
+               t_pop();
 
13166
+               return NULL;
 
13167
+       }
 
13168
+
 
13169
+       if (debug)
 
13170
+               i_info("sieve-storage: using active sieve script path: %s", active_path);
 
13171
+
 
13172
+       /* Get the filename for the active script link */
 
13173
+       active_fname = strrchr(active_path, '/');
 
13174
+       if ( active_fname == NULL ) 
 
13175
+               active_fname = active_path;
 
13176
+       else
 
13177
+               active_fname++;
 
13178
+
 
13179
+       if ( *active_fname == '\0' ) {  
 
13180
+               /* Link cannot be just a path */
 
13181
+               i_error("sieve-storage: Path to active symlink must include "
 
13182
+                       "the link's filename. Path is: %s", active_path);
 
13183
+
 
13184
+               t_pop();
 
13185
+               return NULL;
 
13186
+       }
 
13187
+
 
13188
+       if (debug)
 
13189
+               i_info("sieve-storage: using active sieve script path: %s", active_path);
 
13190
+
 
13191
+       /* Find out where to put the script storage */
 
13192
+
 
13193
+       storage_dir = NULL;
 
13194
+
 
13195
+       if ( data == NULL || *data == '\0' ) {
 
13196
+               /* We'll need to figure out the storage location ourself.
 
13197
+                *
 
13198
+         * It's $HOME/sieve or /sieve when (presumed to be) chrooted.  
 
13199
+                */
 
13200
+               home = getenv("HOME");
 
13201
+        if ( home != NULL && *home != '\0' ) {
 
13202
+                       size_t len;
 
13203
+
 
13204
+            if (access(home, R_OK|W_OK|X_OK) == 0) {
 
13205
+                if (debug) {
 
13206
+                    i_info("sieve-storage: root exists (%s)",
 
13207
+                           home);
 
13208
+                }
 
13209
+
 
13210
+                               /* Check for trailing '/' */
 
13211
+                       len = strlen(home);
 
13212
+                       if (home[len-1] == '/')
 
13213
+                       path = t_strconcat(home, "sieve", NULL);
 
13214
+                               else
 
13215
+                       path = t_strconcat(home, "/sieve", NULL);
 
13216
+                       
 
13217
+                storage_dir = path;
 
13218
+            } else {
 
13219
+                if (debug) {
 
13220
+                    i_info("sieve-storage: access(%s, rwx): "
 
13221
+                           "failed: %m", home);
 
13222
+                }
 
13223
+            }
 
13224
+               } else {
 
13225
+                       if (debug)
 
13226
+                i_info("maildir: HOME not set");
 
13227
+        }
 
13228
+
 
13229
+               if (access("/sieve", R_OK|W_OK|X_OK) == 0) {
 
13230
+            storage_dir = "/sieve";
 
13231
+                       if (debug)
 
13232
+                               i_info("sieve-storage: /sieve exists, assuming chroot");
 
13233
+        }
 
13234
+       } else {
 
13235
+               storage_dir = data;
 
13236
+       }
 
13237
+
 
13238
+       if (storage_dir == NULL || *storage_dir == '\0') {
 
13239
+        if (debug)
 
13240
+            i_info("sieve-storage: couldn't find storage dir");
 
13241
+        return NULL;
 
13242
+    }
 
13243
+
 
13244
+       if (debug)
 
13245
+               i_info("sieve-storage: using sieve script storage directory: %s", storage_dir);    
 
13246
+
 
13247
+       /* Expand home directoties in path */
 
13248
+       storage_dir = home_expand(storage_dir);
 
13249
+       active_path = home_expand(active_path);
 
13250
+
 
13251
+       /* Ensure sieve local directory structure exists (full autocreate):
 
13252
+        *  This currently currently only consists of a ./tmp direcory
 
13253
+        */
 
13254
+       tmp_dir = t_strconcat( storage_dir, "/tmp", NULL );     
 
13255
+       if (mkdir_parents(tmp_dir, CREATE_MODE) < 0 && errno != EEXIST) {
 
13256
+               i_error("sieve-storage: mkdir_parents(%s, CREATE_MODE) failed: %m", tmp_dir);
 
13257
+               t_pop();
 
13258
+               return NULL;
 
13259
+       }
 
13260
+
 
13261
+       /* Create storage object */
 
13262
+       pool = pool_alloconly_create("sieve-storage", 512+256);
 
13263
+    storage = p_new(pool, struct sieve_storage, 1);    
 
13264
+       storage->pool = pool;
 
13265
+       storage->dir = p_strdup(pool, storage_dir);
 
13266
+       storage->user = p_strdup(pool, user);
 
13267
+       storage->active_path = p_strdup(pool, active_path);
 
13268
+       storage->active_fname = p_strdup(pool, active_fname);
 
13269
+
 
13270
+       /* Get the path to be prefixed to the script name in the symlink pointing 
 
13271
+        * to the active script.
 
13272
+        */
 
13273
+       link_path = sieve_storage_get_relative_link_path
 
13274
+               (storage->active_path, storage->dir);
 
13275
+       if (debug)
 
13276
+               i_info("sieve-storage: relative path to sieve storage in active link: %s", link_path);
 
13277
+
 
13278
+       storage->link_path = p_strdup(pool, link_path);
 
13279
+
 
13280
+       t_pop();
 
13281
+       return storage;
 
13282
+}
 
13283
+
 
13284
+void sieve_storage_free(struct sieve_storage *storage)
 
13285
+{
 
13286
+       pool_unref(storage->pool);
 
13287
+}
 
13288
+
 
13289
+void sieve_storage_clear_error(struct sieve_storage *storage)
 
13290
+{
 
13291
+       i_free(storage->error);
 
13292
+       storage->error = NULL;
 
13293
+}
 
13294
+
 
13295
+void sieve_storage_set_error(struct sieve_storage *storage, const char *fmt, ...)
 
13296
+{
 
13297
+       va_list va;
 
13298
+
 
13299
+       sieve_storage_clear_error(storage);
 
13300
+
 
13301
+       if (fmt != NULL) {
 
13302
+               va_start(va, fmt);
 
13303
+               storage->error = i_strdup_vprintf(fmt, va);
 
13304
+               va_end(va);
 
13305
+       }
 
13306
+}
 
13307
+
 
13308
+void sieve_storage_set_internal_error(struct sieve_storage *storage)
 
13309
+{
 
13310
+       struct tm *tm;
 
13311
+       char str[256];
 
13312
+
 
13313
+       tm = localtime(&ioloop_time);
 
13314
+
 
13315
+       i_free(storage->error);
 
13316
+       storage->error =
 
13317
+         strftime(str, sizeof(str), CRITICAL_MSG_STAMP, tm) > 0 ?
 
13318
+         i_strdup(str) : i_strdup(CRITICAL_MSG);
 
13319
+}
 
13320
+
 
13321
+void sieve_storage_set_critical(struct sieve_storage *storage,
 
13322
+             const char *fmt, ...)
 
13323
+{
 
13324
+       va_list va;
 
13325
+       
 
13326
+       sieve_storage_clear_error(storage);
 
13327
+       if (fmt != NULL) {
 
13328
+               va_start(va, fmt);
 
13329
+               i_error("sieve-storage: %s", t_strdup_vprintf(fmt, va));
 
13330
+               va_end(va);
 
13331
+               
 
13332
+               /* critical errors may contain sensitive data, so let user
 
13333
+                  see only "Internal error" with a timestamp to make it
 
13334
+                  easier to look from log files the actual error message. */
 
13335
+               sieve_storage_set_internal_error(storage);
 
13336
+       }
 
13337
+}
 
13338
+
 
13339
+const char *sieve_storage_get_last_error(struct sieve_storage *storage)
 
13340
+{
 
13341
+  /* We get here only in error situations, so we have to return some
 
13342
+     error. If storage->error is NULL, it means we forgot to set it at
 
13343
+     some point.. */
 
13344
+  return storage->error != NULL ? storage->error : "Unknown error";
 
13345
+}
 
13346
+
 
13347
+
 
13348
diff -r 894f003d9f5f src/lib-sievestorage/sieve-storage.h
 
13349
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
13350
+++ b/src/lib-sievestorage/sieve-storage.h      Sun May 04 16:00:59 2008 +0200
 
13351
@@ -0,0 +1,19 @@
 
13352
+#ifndef __SIEVE_STORAGE_H
 
13353
+#define __SIEVE_STORAGE_H
 
13354
+
 
13355
+struct sieve_storage *sieve_storage_create_from_mail(const char *data, const char *user);
 
13356
+struct sieve_storage *sieve_storage_create(const char *data, const char *user);
 
13357
+void sieve_storage_free(struct sieve_storage *storage);
 
13358
+
 
13359
+/* Set error message in storage. Critical errors are logged with i_error(),
 
13360
+   but user sees only "internal error" message. */
 
13361
+void sieve_storage_clear_error(struct sieve_storage *storage);
 
13362
+void sieve_storage_set_error(struct sieve_storage *storage,
 
13363
+          const char *fmt, ...) __attr_format__(2, 3);
 
13364
+void sieve_storage_set_critical(struct sieve_storage *storage,
 
13365
+             const char *fmt, ...) __attr_format__(2, 3);
 
13366
+void sieve_storage_set_internal_error(struct sieve_storage *storage);
 
13367
+
 
13368
+const char *sieve_storage_get_last_error(struct sieve_storage *storage);
 
13369
+
 
13370
+#endif
 
13371
diff -r 894f003d9f5f src/managesieve-login/Makefile.am
 
13372
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
13373
+++ b/src/managesieve-login/Makefile.am Sun May 04 16:00:59 2008 +0200
 
13374
@@ -0,0 +1,29 @@
 
13375
+pkglibexecdir = $(libexecdir)/dovecot
 
13376
+
 
13377
+pkglibexec_PROGRAMS = managesieve-login
 
13378
+
 
13379
+AM_CPPFLAGS = \
 
13380
+       -I$(top_srcdir)/src/lib \
 
13381
+       -I$(top_srcdir)/src/lib-auth \
 
13382
+       -I$(top_srcdir)/src/lib-managesieve \
 
13383
+       -I$(top_srcdir)/src/login-common \
 
13384
+       -I$(top_srcdir)/src/lib-sieve 
 
13385
+
 
13386
+managesieve_login_LDADD = \
 
13387
+       ../login-common/liblogin-common.a \
 
13388
+       ../lib-managesieve/libmanagesieve.a \
 
13389
+       ../lib-sieve/libsieve.la \
 
13390
+       ../lib-sievestorage/libsievestorage.a \
 
13391
+       ../lib-auth/libauth.a \
 
13392
+       ../lib/liblib.a \
 
13393
+       $(SSL_LIBS)
 
13394
+
 
13395
+managesieve_login_SOURCES = \
 
13396
+       client.c \
 
13397
+       client-authenticate.c \
 
13398
+       managesieve-proxy.c
 
13399
+
 
13400
+noinst_HEADERS = \
 
13401
+       client.h \
 
13402
+       client-authenticate.h \
 
13403
+       managesieve-proxy.h
 
13404
diff -r 894f003d9f5f src/managesieve-login/client-authenticate.c
 
13405
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
13406
+++ b/src/managesieve-login/client-authenticate.c       Sun May 04 16:00:59 2008 +0200
 
13407
@@ -0,0 +1,333 @@
 
13408
+#include "common.h"
 
13409
+#include "base64.h"
 
13410
+#include "buffer.h"
 
13411
+#include "ioloop.h"
 
13412
+#include "istream.h"
 
13413
+#include "ostream.h"
 
13414
+#include "safe-memset.h"
 
13415
+#include "str.h"
 
13416
+#include "str-sanitize.h"
 
13417
+
 
13418
+#include <unistd.h>
 
13419
+
 
13420
+#include "managesieve-parser.h"
 
13421
+#include "managesieve-quote.h"
 
13422
+#include "auth-client.h"
 
13423
+#include "client.h"
 
13424
+#include "client-authenticate.h"
 
13425
+#include "managesieve-proxy.h"
 
13426
+
 
13427
+#include <stdlib.h>
 
13428
+
 
13429
+/* FIXME: The use of the ANONYMOUS mechanism is currently denied 
 
13430
+ */
 
13431
+static bool _sasl_mechanism_acceptable
 
13432
+       (const struct auth_mech_desc *mech, bool secured) {
 
13433
+
 
13434
+       /* a) transport is secured
 
13435
+          b) auth mechanism isn't plaintext
 
13436
+       c) we allow insecure authentication
 
13437
+        */
 
13438
+
 
13439
+       if ((mech->flags & MECH_SEC_PRIVATE) == 0 &&
 
13440
+               (mech->flags & MECH_SEC_ANONYMOUS) == 0 &&
 
13441
+               (secured || !disable_plaintext_auth ||
 
13442
+               (mech->flags & MECH_SEC_PLAINTEXT) == 0)) {
 
13443
+               return 1;     
 
13444
+       }  
 
13445
+
 
13446
+       return 0;
 
13447
+}
 
13448
+
 
13449
+const char *client_authenticate_get_capabilities(bool secured)
 
13450
+{
 
13451
+       const struct auth_mech_desc *mech;
 
13452
+       unsigned int i, count;
 
13453
+       string_t *str;
 
13454
+
 
13455
+       str = t_str_new(128);
 
13456
+       mech = auth_client_get_available_mechs(auth_client, &count);
 
13457
+
 
13458
+       if ( count > 0 ) {
 
13459
+               if ( _sasl_mechanism_acceptable(&(mech[0]), secured) ) {
 
13460
+                       str_append(str, mech[0].name);
 
13461
+               }
 
13462
+     
 
13463
+               for (i = 1; i < count; i++) {
 
13464
+                       if ( _sasl_mechanism_acceptable(&(mech[i]), secured) ) {
 
13465
+                               str_append_c(str, ' ');
 
13466
+                               str_append(str, mech[i].name);
 
13467
+                       }
 
13468
+               }
 
13469
+       }
 
13470
+
 
13471
+       return str_c(str);
 
13472
+}
 
13473
+
 
13474
+static void client_auth_input(void *context)
 
13475
+{
 
13476
+       struct managesieve_client *client = context;
 
13477
+       struct managesieve_arg *args;
 
13478
+       const char *msg;
 
13479
+       char *line;
 
13480
+       bool fatal;
 
13481
+
 
13482
+       if (client->destroyed)
 
13483
+               return;
 
13484
+
 
13485
+       if (!client_read(client))
 
13486
+               return;
 
13487
+
 
13488
+       if (client->skip_line) {
 
13489
+               if (i_stream_next_line(client->input) == NULL)
 
13490
+                       return;
 
13491
+
 
13492
+               client->skip_line = FALSE;
 
13493
+       }
 
13494
+
 
13495
+       switch (managesieve_parser_read_args(client->parser, 0, 0, &args)) {
 
13496
+       case -1:
 
13497
+               /* error */
 
13498
+               msg = managesieve_parser_get_error(client->parser, &fatal);
 
13499
+               if (fatal) {
 
13500
+                       /* FIXME: What to do? */
 
13501
+               }
 
13502
+         
 
13503
+               sasl_server_auth_client_error(&client->common, msg);
 
13504
+               return;
 
13505
+       case -2:
 
13506
+               /* not enough data */
 
13507
+               return;
 
13508
+       }
 
13509
+
 
13510
+       if (args[0].type != MANAGESIEVE_ARG_STRING ||
 
13511
+               args[1].type != MANAGESIEVE_ARG_EOL) {
 
13512
+               sasl_server_auth_client_error(&client->common, "Invalid AUTHENTICATE client response.");
 
13513
+               return;
 
13514
+       }
 
13515
+
 
13516
+       line = MANAGESIEVE_ARG_STR(&args[0]);
 
13517
+
 
13518
+       /* Disable input for now */
 
13519
+       if (client->io != NULL)
 
13520
+               io_remove(&client->io);
 
13521
+
 
13522
+    auth_client_request_continue(client->common.auth_request, line);
 
13523
+
 
13524
+       /* clear sensitive data */
 
13525
+       safe_memset(line, 0, strlen(line));
 
13526
+}
 
13527
+
 
13528
+static bool client_handle_args(struct managesieve_client *client,
 
13529
+                              const char *const *args, bool success)
 
13530
+{
 
13531
+       const char *reason = NULL, *host = NULL, *destuser = NULL, *pass = NULL;
 
13532
+       string_t *resp_code;
 
13533
+       unsigned int port = 2000;
 
13534
+       bool proxy = FALSE, temp = FALSE, nologin = !success;
 
13535
+
 
13536
+       for (; *args != NULL; args++) {
 
13537
+               if (strcmp(*args, "nologin") == 0)
 
13538
+                       nologin = TRUE;
 
13539
+               else if (strcmp(*args, "proxy") == 0)
 
13540
+                       proxy = TRUE;
 
13541
+               else if (strcmp(*args, "temp") == 0)
 
13542
+                       temp = TRUE;
 
13543
+               else if (strncmp(*args, "reason=", 7) == 0)
 
13544
+                       reason = *args + 7;
 
13545
+               else if (strncmp(*args, "host=", 5) == 0)
 
13546
+                       host = *args + 5;
 
13547
+               else if (strncmp(*args, "port=", 5) == 0)
 
13548
+                       port = atoi(*args + 5);
 
13549
+               else if (strncmp(*args, "destuser=", 9) == 0)
 
13550
+                       destuser = *args + 9;
 
13551
+               else if (strncmp(*args, "pass=", 5) == 0)
 
13552
+                       pass = *args + 5;
 
13553
+       }
 
13554
+
 
13555
+       if (destuser == NULL)
 
13556
+               destuser = client->common.virtual_user;
 
13557
+
 
13558
+       if (proxy) {
 
13559
+               /* we want to proxy the connection to another server.
 
13560
+               don't do this unless authentication succeeded. with
 
13561
+               master user proxying we can get FAIL with proxy still set.
 
13562
+
 
13563
+               proxy host=.. [port=..] [destuser=..] pass=.. */
 
13564
+
 
13565
+               if (!success)
 
13566
+                       return FALSE;
 
13567
+               if (managesieve_proxy_new(client, host, port, destuser, pass) < 0)
 
13568
+                       client_destroy_internal_failure(client);
 
13569
+               return TRUE;
 
13570
+       }
 
13571
+
 
13572
+       if (host != NULL) {
 
13573
+               /* MANAGESIEVE referral
 
13574
+
 
13575
+                  [nologin] referral host=.. [port=..] [destuser=..]
 
13576
+                  [reason=..]
 
13577
+
 
13578
+                  NO (REFERRAL sieve://user;AUTH=mech@host:port/) Can't login.
 
13579
+                  OK (...) Logged in, but you should use this server instead.
 
13580
+                  .. [REFERRAL ..] (Reason from auth server)
 
13581
+               */
 
13582
+               resp_code = t_str_new(128);
 
13583
+               str_printfa(resp_code, "REFERRAL sieve://%s;AUTH=%s@%s",
 
13584
+                           destuser, client->common.auth_mech_name, host);
 
13585
+               if (port != 2000)
 
13586
+                       str_printfa(resp_code, ":%u", port);
 
13587
+
 
13588
+               if (reason == NULL) {
 
13589
+                       if (nologin)
 
13590
+                               reason = "Try this server instead.";
 
13591
+                       else 
 
13592
+                               reason = "Logged in, but you should use "
 
13593
+                                       "this server instead.";
 
13594
+               }
 
13595
+
 
13596
+               if (!nologin) {
 
13597
+                       client_send_okresp(client, str_c(resp_code), reason);
 
13598
+                       client_destroy(client, "Login with referral");
 
13599
+                       return TRUE;
 
13600
+               }
 
13601
+               client_send_noresp(client, str_c(resp_code), reason);
 
13602
+       } else if (nologin) {
 
13603
+               /* Authentication went ok, but for some reason user isn't
 
13604
+                  allowed to log in. Shouldn't probably happen. */
 
13605
+               if (reason != NULL)
 
13606
+                       client_send_no(client, reason);
 
13607
+               else if (temp)
 
13608
+                       client_send_no(client, AUTH_TEMP_FAILED_MSG);           
 
13609
+               else
 
13610
+                       client_send_no(client, AUTH_FAILED_MSG);
 
13611
+       } else {
 
13612
+               /* normal login/failure */
 
13613
+               return FALSE;
 
13614
+       }
 
13615
+
 
13616
+       i_assert(nologin);
 
13617
+
 
13618
+       managesieve_parser_reset(client->parser);
 
13619
+
 
13620
+       if (!client->destroyed) {
 
13621
+               /* get back to normal client input. */
 
13622
+               if (client->io != NULL)
 
13623
+                       io_remove(&client->io);
 
13624
+               client->io = io_add(client->common.fd, IO_READ,
 
13625
+                       client_input, client);
 
13626
+       }
 
13627
+
 
13628
+       return TRUE;
 
13629
+}
 
13630
+
 
13631
+static void sasl_callback(struct client *_client, enum sasl_server_reply reply,
 
13632
+                         const char *data, const char *const *args)
 
13633
+{
 
13634
+       struct managesieve_client *client = (struct managesieve_client *)_client;
 
13635
+       string_t *str;
 
13636
+
 
13637
+       i_assert(!client->destroyed ||
 
13638
+               reply == SASL_SERVER_REPLY_CLIENT_ERROR ||
 
13639
+               reply == SASL_SERVER_REPLY_MASTER_FAILED);
 
13640
+
 
13641
+       client->skip_line = TRUE;
 
13642
+
 
13643
+       switch (reply) {
 
13644
+       case SASL_SERVER_REPLY_SUCCESS:
 
13645
+               if (args != NULL) {
 
13646
+                       if (client_handle_args(client, args, TRUE))
 
13647
+                               break;
 
13648
+               }
 
13649
+
 
13650
+               client_destroy(client, "Login");
 
13651
+               break;
 
13652
+       case SASL_SERVER_REPLY_AUTH_FAILED:
 
13653
+       case SASL_SERVER_REPLY_CLIENT_ERROR:
 
13654
+               if (args != NULL) {
 
13655
+                       if (client_handle_args(client, args, FALSE))
 
13656
+                               break;
 
13657
+               }
 
13658
+
 
13659
+               client_send_no(client, data != NULL ? data : AUTH_FAILED_MSG);
 
13660
+
 
13661
+               managesieve_parser_reset(client->parser);
 
13662
+
 
13663
+               if (!client->destroyed) {                                       
 
13664
+                       /* get back to normal client input. */
 
13665
+                       if (client->io != NULL)
 
13666
+                               io_remove(&client->io);
 
13667
+                       client->io = io_add(client->common.fd, IO_READ,
 
13668
+                                       client_input, client);
 
13669
+               }
 
13670
+               break;
 
13671
+       case SASL_SERVER_REPLY_MASTER_FAILED:
 
13672
+               client_destroy_internal_failure(client);
 
13673
+               break;
 
13674
+       case SASL_SERVER_REPLY_CONTINUE:
 
13675
+               t_push();
 
13676
+               str = t_str_new(256);
 
13677
+               managesieve_quote_append_string(str, data, TRUE);
 
13678
+               str_append(str, "\r\n");
 
13679
+                               
 
13680
+               /* don't check return value here. it gets tricky if we try
 
13681
+                  to call client_destroy() in here. */
 
13682
+               (void)o_stream_send(client->output, str_c(str), str_len(str));
 
13683
+               t_pop();
 
13684
+
 
13685
+               managesieve_parser_reset(client->parser);
 
13686
+
 
13687
+               i_assert(client->io == NULL);
 
13688
+        client->io = io_add(client->common.fd, IO_READ,
 
13689
+                    client_auth_input, client);
 
13690
+        client_auth_input(client);
 
13691
+               
 
13692
+               return;
 
13693
+       }
 
13694
+
 
13695
+       client_unref(client);
 
13696
+}
 
13697
+
 
13698
+int cmd_authenticate(struct managesieve_client *client, struct managesieve_arg *args)
 
13699
+{
 
13700
+       const char *mech_name, *init_resp = NULL;
 
13701
+
 
13702
+       /* one mandatory argument: authentication mechanism name */
 
13703
+       if (args[0].type != MANAGESIEVE_ARG_STRING)
 
13704
+               return -1;
 
13705
+       if (args[1].type != MANAGESIEVE_ARG_EOL) {
 
13706
+               /* optional SASL initial response */
 
13707
+               if (args[1].type != MANAGESIEVE_ARG_STRING ||
 
13708
+                   args[2].type != MANAGESIEVE_ARG_EOL)
 
13709
+                       return -1;
 
13710
+               init_resp = MANAGESIEVE_ARG_STR(&args[1]);
 
13711
+       }
 
13712
+
 
13713
+       mech_name = MANAGESIEVE_ARG_STR(&args[0]);
 
13714
+       if (*mech_name == '\0') 
 
13715
+               return -1;
 
13716
+
 
13717
+       /* FIXME: This refuses the ANONYMOUS mechanism. 
 
13718
+        *   This can be removed once anonymous login is implemented according to the 
 
13719
+        *   draft RFC. - Stephan
 
13720
+        */
 
13721
+       if ( strncasecmp(mech_name, "ANONYMOUS", 9) == 0 ) {
 
13722
+               client_send_no(client, "ANONYMOUS mechanism is not implemented.");              
 
13723
+               return 0;
 
13724
+       }
 
13725
+
 
13726
+       client_ref(client);
 
13727
+       sasl_server_auth_begin(&client->common, "MANAGESIEVE", mech_name,
 
13728
+                              init_resp, sasl_callback);
 
13729
+       if (!client->common.authenticating)
 
13730
+               return 1;
 
13731
+
 
13732
+       /* don't handle input until we get the initial auth reply */
 
13733
+       if (client->io != NULL)
 
13734
+               io_remove(&client->io);
 
13735
+
 
13736
+       managesieve_parser_reset(client->parser);
 
13737
+
 
13738
+       return 0;
 
13739
+}
 
13740
+
 
13741
diff -r 894f003d9f5f src/managesieve-login/client-authenticate.h
 
13742
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
13743
+++ b/src/managesieve-login/client-authenticate.h       Sun May 04 16:00:59 2008 +0200
 
13744
@@ -0,0 +1,9 @@
 
13745
+#ifndef __CLIENT_AUTHENTICATE_H
 
13746
+#define __CLIENT_AUTHENTICATE_H
 
13747
+
 
13748
+const char *client_authenticate_get_capabilities(bool secured);
 
13749
+
 
13750
+int cmd_login(struct managesieve_client *client, struct managesieve_arg *args);
 
13751
+int cmd_authenticate(struct managesieve_client *client, struct managesieve_arg *args);
 
13752
+
 
13753
+#endif
 
13754
diff -r 894f003d9f5f src/managesieve-login/client.c
 
13755
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
13756
+++ b/src/managesieve-login/client.c    Sun May 04 16:00:59 2008 +0200
 
13757
@@ -0,0 +1,680 @@
 
13758
+#include "common.h"
 
13759
+#include "buffer.h"
 
13760
+#include "hash.h"
 
13761
+#include "ioloop.h"
 
13762
+#include "istream.h"
 
13763
+#include "ostream.h"
 
13764
+#include "process-title.h"
 
13765
+#include "safe-memset.h"
 
13766
+#include "str.h"
 
13767
+#include "strfuncs.h"
 
13768
+#include "strescape.h"
 
13769
+#include "managesieve-parser.h"
 
13770
+#include "managesieve-quote.h"
 
13771
+#include "sieve-implementation.h"
 
13772
+
 
13773
+#include "client.h"
 
13774
+#include "client-authenticate.h"
 
13775
+#include "auth-client.h"
 
13776
+#include "ssl-proxy.h"
 
13777
+#include "managesieve-proxy.h"
 
13778
+
 
13779
+#include <stdlib.h>
 
13780
+
 
13781
+/* max. size of one parameter in line, or max reply length in SASL
 
13782
+   authentication */
 
13783
+#define MAX_INBUF_SIZE 4096
 
13784
+
 
13785
+/* max. size of output buffer. if it gets full, the client is disconnected.
 
13786
+   SASL authentication gives the largest output. */
 
13787
+#define MAX_OUTBUF_SIZE 4096
 
13788
+
 
13789
+/* Disconnect client after idling this many seconds */
 
13790
+#define CLIENT_LOGIN_IDLE_TIMEOUT 60
 
13791
+
 
13792
+/* Disconnect client when it sends too many bad commands */
 
13793
+#define CLIENT_MAX_BAD_COMMANDS 10
 
13794
+
 
13795
+/* When max. number of simultaneous connections is reached, few of the
 
13796
+   oldest connections are disconnected. Since we have to go through the whole
 
13797
+   client hash, it's faster if we disconnect multiple clients. */
 
13798
+#define CLIENT_DESTROY_OLDEST_COUNT 16
 
13799
+
 
13800
+#if CLIENT_LOGIN_IDLE_TIMEOUT >= AUTH_REQUEST_TIMEOUT
 
13801
+#  error client idle timeout must be smaller than authentication timeout
 
13802
+#endif
 
13803
+
 
13804
+const char *login_protocol = "MANAGESIEVE";
 
13805
+const char *capability_string = CAPABILITY_STRING;
 
13806
+
 
13807
+const char *managesieve_implementation_string;
 
13808
+
 
13809
+static struct hash_table *clients;
 
13810
+static struct timeout *to_idle;
 
13811
+
 
13812
+static void client_set_title(struct managesieve_client *client)
 
13813
+{
 
13814
+       const char *addr;
 
13815
+
 
13816
+       if (!verbose_proctitle || !process_per_connection)
 
13817
+               return;
 
13818
+
 
13819
+       addr = net_ip2addr(&client->common.ip);
 
13820
+       if (addr == NULL)
 
13821
+               addr = "??";
 
13822
+
 
13823
+       process_title_set(t_strdup_printf(client->common.tls ?
 
13824
+                                         "[%s TLS]" : "[%s]", addr));
 
13825
+}
 
13826
+
 
13827
+static void client_open_streams(struct managesieve_client *client, int fd)
 
13828
+{
 
13829
+       client->input = i_stream_create_file(fd, default_pool,
 
13830
+                                            MAX_INBUF_SIZE, FALSE);
 
13831
+       client->output = o_stream_create_file(fd, default_pool, MAX_OUTBUF_SIZE,
 
13832
+                                             FALSE);
 
13833
+       client->parser = managesieve_parser_create(client->input, client->output,
 
13834
+                                           MAX_MANAGESIEVE_LINE);
 
13835
+}
 
13836
+
 
13837
+/* Skip incoming data until newline is found,
 
13838
+   returns TRUE if newline was found. */
 
13839
+bool client_skip_line(struct managesieve_client *client)
 
13840
+{
 
13841
+       const unsigned char *data;
 
13842
+       size_t i, data_size;
 
13843
+
 
13844
+       data = i_stream_get_data(client->input, &data_size);
 
13845
+
 
13846
+       for (i = 0; i < data_size; i++) {
 
13847
+               if (data[i] == '\n') {
 
13848
+                       i_stream_skip(client->input, i+1);
 
13849
+                       return TRUE;
 
13850
+               }
 
13851
+       }
 
13852
+
 
13853
+       return FALSE;
 
13854
+}
 
13855
+
 
13856
+static void client_send_capabilities(struct managesieve_client *client)
 
13857
+{
 
13858
+       const char *auths;
 
13859
+       const char *sievecap, *sieveimpl;
 
13860
+
 
13861
+       sievecap = sieve_get_capabilities();
 
13862
+       if (sievecap == NULL)
 
13863
+               sievecap = "";
 
13864
+
 
13865
+       t_push();
 
13866
+       sievecap = t_strconcat("\"SIEVE\" \"", sievecap, "\"", NULL);
 
13867
+       sieveimpl = t_strconcat("\"IMPLEMENTATION\" \"",
 
13868
+    managesieve_implementation_string, "\"", NULL);
 
13869
+
 
13870
+       auths = client_authenticate_get_capabilities(client->common.secured);
 
13871
+
 
13872
+       /* We assume no MANAGESIEVE-string incompatible values are produced here */
 
13873
+       client_send_line(client, sieveimpl);
 
13874
+       client_send_line(client, t_strconcat("\"SASL\" \"", auths, "\"", NULL) );
 
13875
+       client_send_line(client, sievecap);
 
13876
+
 
13877
+       if (ssl_initialized && !client->common.tls)
 
13878
+               client_send_line(client, "\"STARTTLS\"" );
 
13879
+
 
13880
+       t_pop();
 
13881
+}
 
13882
+
 
13883
+static int cmd_capability(struct managesieve_client *client)
 
13884
+{
 
13885
+       client_send_capabilities(client);
 
13886
+       client_send_ok(client, "Capability completed.");
 
13887
+       return TRUE;
 
13888
+}
 
13889
+
 
13890
+static void client_start_tls(struct managesieve_client *client)
 
13891
+{
 
13892
+       int fd_ssl;
 
13893
+
 
13894
+    client_ref(client);
 
13895
+    connection_queue_add(1);
 
13896
+    if (!client_unref(client) || client->destroyed)
 
13897
+        return;
 
13898
+
 
13899
+       fd_ssl = ssl_proxy_new(client->common.fd, &client->common.ip,
 
13900
+                              &client->common.proxy);
 
13901
+       if (fd_ssl == -1) {
 
13902
+               client_send_bye(client, "TLS initialization failed.");
 
13903
+               client_destroy(client, "TLS initialization failed.");
 
13904
+               return;
 
13905
+       }
 
13906
+
 
13907
+       client->common.tls = TRUE;
 
13908
+       client->common.secured = TRUE;
 
13909
+       client_set_title(client);
 
13910
+
 
13911
+       client->common.fd = fd_ssl;
 
13912
+       i_stream_unref(&client->input);
 
13913
+       o_stream_unref(&client->output);
 
13914
+       managesieve_parser_destroy(&client->parser);
 
13915
+
 
13916
+       /* CRLF is lost from buffer when streams are reopened. */
 
13917
+       client->skip_line = FALSE;
 
13918
+
 
13919
+       client_open_streams(client, fd_ssl);
 
13920
+       client->io = io_add(client->common.fd, IO_READ, client_input, client);
 
13921
+}
 
13922
+
 
13923
+static int client_output_starttls(void *context)
 
13924
+{
 
13925
+       struct managesieve_client *client = context;
 
13926
+       int ret;
 
13927
+
 
13928
+       if ((ret = o_stream_flush(client->output)) < 0) {
 
13929
+               client_destroy(client, "Disconnected");
 
13930
+               return 1;
 
13931
+       }
 
13932
+
 
13933
+       if (ret > 0) {
 
13934
+               o_stream_set_flush_callback(client->output, NULL, NULL);
 
13935
+               client_start_tls(client);
 
13936
+       }
 
13937
+       return 1;
 
13938
+}
 
13939
+
 
13940
+static int cmd_starttls(struct managesieve_client *client)
 
13941
+{
 
13942
+       if (client->common.tls) {
 
13943
+               client_send_no(client, "TLS is already active.");
 
13944
+               return 1;
 
13945
+       }
 
13946
+
 
13947
+       if (!ssl_initialized) {
 
13948
+               client_send_no(client, "TLS support isn't enabled.");
 
13949
+               return 1;
 
13950
+       }
 
13951
+
 
13952
+       /* remove input handler, SSL proxy gives us a new fd. we also have to
 
13953
+          remove it in case we have to wait for buffer to be flushed */
 
13954
+       if (client->io != NULL)
 
13955
+               io_remove(&client->io);
 
13956
+
 
13957
+       client_send_ok(client, "Begin TLS negotiation now.");
 
13958
+
 
13959
+       /* uncork the old fd */
 
13960
+       o_stream_uncork(client->output);
 
13961
+
 
13962
+       if (o_stream_flush(client->output) <= 0) {
 
13963
+               /* the buffer has to be flushed */
 
13964
+               o_stream_set_flush_pending(client->output, TRUE);
 
13965
+               o_stream_set_flush_callback(client->output,
 
13966
+                                           client_output_starttls, client);
 
13967
+       } else {
 
13968
+               client_start_tls(client);
 
13969
+       }
 
13970
+
 
13971
+    /* Cork the stream to send the capability data as a single tcp frame
 
13972
+     *   Some naive clients break if we don't.
 
13973
+     */
 
13974
+    o_stream_cork(client->output);
 
13975
+
 
13976
+       client_send_capabilities(client);
 
13977
+       client_send_ok(client, "TLS negotiation successful.");
 
13978
+
 
13979
+    o_stream_uncork(client->output);
 
13980
+
 
13981
+       return 1;
 
13982
+}
 
13983
+
 
13984
+static int cmd_logout(struct managesieve_client *client)
 
13985
+{
 
13986
+       client_send_ok(client, "Logout completed.");
 
13987
+       client_destroy(client, "Aborted login (logout command)");
 
13988
+       return 1;
 
13989
+}
 
13990
+
 
13991
+static int client_command_execute(struct managesieve_client *client, const char *cmd,
 
13992
+                                 struct managesieve_arg *args)
 
13993
+{
 
13994
+       cmd = t_str_ucase(cmd);
 
13995
+       if (strcmp(cmd, "AUTHENTICATE") == 0)
 
13996
+               return cmd_authenticate(client, args);
 
13997
+       if (strcmp(cmd, "CAPABILITY") == 0)
 
13998
+               return cmd_capability(client);
 
13999
+       if (strcmp(cmd, "STARTTLS") == 0)
 
14000
+               return cmd_starttls(client);
 
14001
+       if (strcmp(cmd, "LOGOUT") == 0)
 
14002
+               return cmd_logout(client);
 
14003
+
 
14004
+       return -1;
 
14005
+}
 
14006
+
 
14007
+static bool client_handle_input(struct managesieve_client *client)
 
14008
+{
 
14009
+       struct managesieve_arg *args;
 
14010
+       const char *msg;
 
14011
+       int ret;
 
14012
+       bool fatal;
 
14013
+
 
14014
+       i_assert(!client->common.authenticating);
 
14015
+
 
14016
+       if (client->cmd_finished) {
 
14017
+               /* clear the previous command from memory. don't do this
 
14018
+                  immediately after handling command since we need the
 
14019
+                  cmd_tag to stay some time after authentication commands. */
 
14020
+               client->cmd_name = NULL;
 
14021
+               managesieve_parser_reset(client->parser);
 
14022
+
 
14023
+               /* remove \r\n */
 
14024
+               if (client->skip_line) {
 
14025
+                       if (!client_skip_line(client))
 
14026
+                               return FALSE;
 
14027
+                       client->skip_line = FALSE;
 
14028
+               }
 
14029
+
 
14030
+               client->cmd_finished = FALSE;
 
14031
+       }
 
14032
+
 
14033
+       if (client->cmd_name == NULL) {
 
14034
+               client->cmd_name = managesieve_parser_read_word(client->parser);
 
14035
+               if (client->cmd_name == NULL)
 
14036
+                       return FALSE; /* need more data */
 
14037
+       }
 
14038
+
 
14039
+       switch (managesieve_parser_read_args(client->parser, 0, 0, &args)) {
 
14040
+       case -1:
 
14041
+               /* error */
 
14042
+               msg = managesieve_parser_get_error(client->parser, &fatal);
 
14043
+               if (fatal) {
 
14044
+                       client_send_bye(client, msg);
 
14045
+                       client_destroy(client, t_strconcat("Disconnected: ",
 
14046
+                                                          msg, NULL));
 
14047
+                       return FALSE;
 
14048
+               }
 
14049
+
 
14050
+               client_send_no(client, msg);
 
14051
+               client->cmd_finished = TRUE;
 
14052
+               client->skip_line = TRUE;
 
14053
+               return TRUE;
 
14054
+       case -2:
 
14055
+               /* not enough data */
 
14056
+               return FALSE;
 
14057
+       }
 
14058
+       client->skip_line = TRUE;
 
14059
+
 
14060
+       ret = client_command_execute(client, client->cmd_name, args);
 
14061
+
 
14062
+       client->cmd_finished = TRUE;
 
14063
+       if (ret < 0) {
 
14064
+               if (++client->bad_counter >= CLIENT_MAX_BAD_COMMANDS) {
 
14065
+                       client_send_bye(client, 
 
14066
+                               "Too many invalid MANAGESIEVE commands.");
 
14067
+                       client_destroy(client, "Disconnected: "
 
14068
+                               "Too many invalid commands.");
 
14069
+                       return FALSE;
 
14070
+               }  
 
14071
+               client_send_no(client,
 
14072
+                       "Error in MANAGESIEVE command received by server.");
 
14073
+       }
 
14074
+
 
14075
+       return ret != 0;
 
14076
+}
 
14077
+
 
14078
+bool client_read(struct managesieve_client *client)
 
14079
+{
 
14080
+       switch (i_stream_read(client->input)) {
 
14081
+       case -2:
 
14082
+               /* buffer full */
 
14083
+               client_send_bye(client, "Input buffer full, aborting");
 
14084
+               client_destroy(client, "Disconnected: Input buffer full");
 
14085
+               return FALSE;
 
14086
+       case -1:
 
14087
+               /* disconnected */
 
14088
+               client_destroy(client, "Disconnected");
 
14089
+               return FALSE;
 
14090
+       default:
 
14091
+               /* something was read */
 
14092
+               return TRUE;
 
14093
+       }
 
14094
+}
 
14095
+
 
14096
+void client_input(void *context)
 
14097
+{
 
14098
+       struct managesieve_client *client = context;
 
14099
+
 
14100
+       client->last_input = ioloop_time;
 
14101
+
 
14102
+       if (!client_read(client))
 
14103
+               return;
 
14104
+
 
14105
+       client_ref(client);
 
14106
+
 
14107
+       if (!auth_client_is_connected(auth_client)) {
 
14108
+               /* we're not yet connected to auth process -
 
14109
+                  don't allow any commands */
 
14110
+               /* FIXME: Can't do this with managesieve. Any other ways?
 
14111
+               client_send_ok(client,
 
14112
+               "Waiting for authentication process to respond.");
 
14113
+               */
 
14114
+               client->input_blocked = TRUE;
 
14115
+       } else {
 
14116
+               o_stream_cork(client->output);
 
14117
+               while (client_handle_input(client)) ;
 
14118
+               o_stream_uncork(client->output);
 
14119
+       }
 
14120
+
 
14121
+       client_unref(client);
 
14122
+}
 
14123
+
 
14124
+void client_destroy_oldest(void)
 
14125
+{
 
14126
+       struct hash_iterate_context *iter;
 
14127
+       void *key, *value;
 
14128
+       struct managesieve_client *destroy_buf[CLIENT_DESTROY_OLDEST_COUNT];
 
14129
+       int i, destroy_count;
 
14130
+
 
14131
+       /* find the oldest clients and put them to destroy-buffer */
 
14132
+       memset(destroy_buf, 0, sizeof(destroy_buf));
 
14133
+
 
14134
+       destroy_count = max_connections > CLIENT_DESTROY_OLDEST_COUNT*2 ?
 
14135
+        CLIENT_DESTROY_OLDEST_COUNT : I_MIN(max_connections/2, 1);
 
14136
+    iter = hash_iterate_init(clients);
 
14137
+    while (hash_iterate(iter, &key, &value)) {
 
14138
+        struct managesieve_client *client = key;
 
14139
+
 
14140
+        for (i = 0; i < destroy_count; i++) {
 
14141
+            if (destroy_buf[i] == NULL ||
 
14142
+                destroy_buf[i]->created > client->created) {
 
14143
+                /* @UNSAFE */
 
14144
+                memmove(destroy_buf+i+1, destroy_buf+i,
 
14145
+                    sizeof(destroy_buf) -
 
14146
+                    (i+1) * sizeof(struct managesieve_client *));
 
14147
+                destroy_buf[i] = client;
 
14148
+                break;
 
14149
+            }
 
14150
+        }
 
14151
+    }
 
14152
+    hash_iterate_deinit(iter);
 
14153
+
 
14154
+    /* then kill them */
 
14155
+    for (i = 0; i < destroy_count; i++) {
 
14156
+        if (destroy_buf[i] == NULL)
 
14157
+            break;
 
14158
+
 
14159
+        client_destroy(destroy_buf[i],
 
14160
+                   "Disconnected: Connection queue full");
 
14161
+    }
 
14162
+}
 
14163
+
 
14164
+static void client_send_greeting(struct managesieve_client *client)
 
14165
+{
 
14166
+       /* Cork the stream to send the capability data as a single tcp frame
 
14167
+     *   Some naive clients break if we don't.
 
14168
+     */
 
14169
+    o_stream_cork(client->output);
 
14170
+
 
14171
+       /* Send initial capabilities */   
 
14172
+       client_send_capabilities(client);
 
14173
+       client_send_ok(client, greeting);
 
14174
+       client->greeting_sent = TRUE;
 
14175
+
 
14176
+    o_stream_uncork(client->output);
 
14177
+}
 
14178
+
 
14179
+struct client *client_create(int fd, bool ssl, const struct ip_addr *local_ip,
 
14180
+                            const struct ip_addr *ip)
 
14181
+{
 
14182
+  struct managesieve_client *client;
 
14183
+
 
14184
+  i_assert(fd != -1);
 
14185
+
 
14186
+  connection_queue_add(1);
 
14187
+
 
14188
+  /* always use nonblocking I/O */
 
14189
+  net_set_nonblock(fd, TRUE);
 
14190
+
 
14191
+  client = i_new(struct managesieve_client, 1);
 
14192
+  client->created = ioloop_time;
 
14193
+  client->refcount = 1;
 
14194
+  client->common.tls = ssl;
 
14195
+  client->common.secured = ssl || net_ip_compare(ip, local_ip);
 
14196
+
 
14197
+  client->common.local_ip = *local_ip;
 
14198
+  client->common.ip = *ip;
 
14199
+  client->common.fd = fd;
 
14200
+
 
14201
+  client_open_streams(client, fd);
 
14202
+  client->io = io_add(fd, IO_READ, client_input, client);
 
14203
+
 
14204
+  client->last_input = ioloop_time;
 
14205
+  hash_insert(clients, client, client);
 
14206
+
 
14207
+  main_ref();
 
14208
+
 
14209
+  if (!greeting_capability || auth_client_is_connected(auth_client))
 
14210
+                client_send_greeting(client);
 
14211
+  client_set_title(client);
 
14212
+
 
14213
+  return &client->common;
 
14214
+}
 
14215
+
 
14216
+void client_destroy(struct managesieve_client *client, const char *reason)
 
14217
+{
 
14218
+       if (client->destroyed)
 
14219
+               return;
 
14220
+       client->destroyed = TRUE;
 
14221
+
 
14222
+       if (reason != NULL)
 
14223
+               client_syslog(&client->common, reason);
 
14224
+
 
14225
+       hash_remove(clients, client);
 
14226
+
 
14227
+       if (client->input != NULL)
 
14228
+               i_stream_close(client->input);
 
14229
+       if (client->output != NULL)
 
14230
+               o_stream_close(client->output);
 
14231
+
 
14232
+       if (client->common.master_tag != 0)
 
14233
+        master_request_abort(&client->common);
 
14234
+
 
14235
+    if (client->common.auth_request != NULL) {
 
14236
+        i_assert(client->common.authenticating);
 
14237
+        sasl_server_auth_client_error(&client->common, NULL);
 
14238
+    } else {
 
14239
+        i_assert(!client->common.authenticating);
 
14240
+    }
 
14241
+
 
14242
+       if (client->io != NULL)
 
14243
+               io_remove(&client->io);
 
14244
+   
 
14245
+       if (client->common.fd != -1) {
 
14246
+               net_disconnect(client->common.fd);
 
14247
+               client->common.fd = -1;
 
14248
+       }
 
14249
+
 
14250
+       if (client->proxy_password != NULL) {
 
14251
+        safe_memset(client->proxy_password, 0,
 
14252
+                strlen(client->proxy_password));
 
14253
+        i_free(client->proxy_password);
 
14254
+        client->proxy_password = NULL;
 
14255
+    }
 
14256
+
 
14257
+    i_free(client->proxy_user);
 
14258
+    client->proxy_user = NULL;
 
14259
+
 
14260
+    if (client->proxy != NULL) {
 
14261
+        login_proxy_free(client->proxy);
 
14262
+        client->proxy = NULL;
 
14263
+    }
 
14264
+
 
14265
+    if (client->common.proxy != NULL) {
 
14266
+        ssl_proxy_free(client->common.proxy);
 
14267
+        client->common.proxy = NULL;
 
14268
+    }
 
14269
+
 
14270
+    client_unref(client);
 
14271
+
 
14272
+    main_listen_start();
 
14273
+    main_unref();
 
14274
+}
 
14275
+
 
14276
+void client_destroy_internal_failure(struct managesieve_client *client)
 
14277
+{
 
14278
+       client_send_byeresp(client, "TRYLATER", "Internal login failure. "
 
14279
+               "Refer to server log for more information.");
 
14280
+       client_destroy(client, "Internal login failure");
 
14281
+}
 
14282
+
 
14283
+void client_ref(struct managesieve_client *client)
 
14284
+{
 
14285
+       client->refcount++;
 
14286
+}
 
14287
+
 
14288
+bool client_unref(struct managesieve_client *client)
 
14289
+{
 
14290
+       i_assert(client->refcount > 0);
 
14291
+       if (--client->refcount > 0)
 
14292
+               return TRUE;
 
14293
+
 
14294
+       i_assert(client->destroyed);
 
14295
+
 
14296
+       managesieve_parser_destroy(&client->parser);
 
14297
+
 
14298
+       if (client->input != NULL)
 
14299
+               i_stream_unref(&client->input);
 
14300
+       if (client->output != NULL)
 
14301
+               o_stream_unref(&client->output);
 
14302
+
 
14303
+       i_free(client->common.virtual_user);
 
14304
+       i_free(client->common.auth_mech_name);
 
14305
+       i_free(client);
 
14306
+
 
14307
+       return FALSE;
 
14308
+}
 
14309
+
 
14310
+void client_send_line(struct managesieve_client *client, const char *line)
 
14311
+{
 
14312
+       struct const_iovec iov[2];
 
14313
+       ssize_t ret;
 
14314
+
 
14315
+       iov[0].iov_base = line;
 
14316
+       iov[0].iov_len = strlen(line);
 
14317
+       iov[1].iov_base = "\r\n";
 
14318
+       iov[1].iov_len = 2;
 
14319
+
 
14320
+       ret = o_stream_sendv(client->output, iov, 2);
 
14321
+       if (ret < 0 || (size_t)ret != iov[0].iov_len + iov[1].iov_len) {
 
14322
+               /* either disconnection or buffer full. in either case we
 
14323
+                  want this connection destroyed. however destroying it here
 
14324
+                  might break things if client is still tried to be accessed
 
14325
+                  without being referenced.. */
 
14326
+               i_stream_close(client->input);
 
14327
+       }
 
14328
+}
 
14329
+
 
14330
+void _client_send_response(struct managesieve_client *client, 
 
14331
+       const char *oknobye, const char *resp_code, const char *msg)
 
14332
+{
 
14333
+       string_t *str;
 
14334
+
 
14335
+       str = t_str_new(128);
 
14336
+       str_append(str, oknobye);
 
14337
+
 
14338
+       if ( resp_code != NULL )
 
14339
+       {
 
14340
+               str_append(str, " (");
 
14341
+               str_append(str, resp_code);
 
14342
+               str_append_c(str, ')');
 
14343
+       }
 
14344
+
 
14345
+       if ( msg != NULL )      
 
14346
+       {
 
14347
+               str_append_c(str, ' ');
 
14348
+               managesieve_quote_append_string(str, msg, TRUE);
 
14349
+       }
 
14350
+
 
14351
+       client_send_line(client, str_c(str));
 
14352
+}
 
14353
+
 
14354
+static void client_check_idle(struct managesieve_client *client)
 
14355
+{
 
14356
+       if (ioloop_time - client->last_input >= CLIENT_LOGIN_IDLE_TIMEOUT) {
 
14357
+               client_send_bye(client, "Disconnected for inactivity.");
 
14358
+               client_destroy(client, "Disconnected: Inactivity");
 
14359
+       }
 
14360
+}
 
14361
+
 
14362
+static void idle_timeout(void *context __attr_unused__)
 
14363
+{
 
14364
+       struct hash_iterate_context *iter;
 
14365
+       void *key, *value;
 
14366
+
 
14367
+       iter = hash_iterate_init(clients);
 
14368
+       while (hash_iterate(iter, &key, &value)) {
 
14369
+               struct managesieve_client *client = key;
 
14370
+
 
14371
+               client_check_idle(client);
 
14372
+       }
 
14373
+       hash_iterate_deinit(iter);
 
14374
+}
 
14375
+
 
14376
+unsigned int clients_get_count(void)
 
14377
+{
 
14378
+       return hash_size(clients);
 
14379
+}
 
14380
+
 
14381
+void clients_notify_auth_connected(void)
 
14382
+{
 
14383
+       struct hash_iterate_context *iter;
 
14384
+       void *key, *value;
 
14385
+
 
14386
+       iter = hash_iterate_init(clients);
 
14387
+       while (hash_iterate(iter, &key, &value)) {
 
14388
+               struct managesieve_client *client = key;
 
14389
+
 
14390
+               if (!client->greeting_sent)
 
14391
+                       client_send_greeting(client);
 
14392
+               if (client->input_blocked) {
 
14393
+                       client->input_blocked = FALSE;
 
14394
+                       client_input(client);
 
14395
+               }
 
14396
+       }
 
14397
+       hash_iterate_deinit(iter);
 
14398
+}
 
14399
+
 
14400
+void clients_destroy_all(void)
 
14401
+{
 
14402
+       struct hash_iterate_context *iter;
 
14403
+       void *key, *value;
 
14404
+
 
14405
+       iter = hash_iterate_init(clients);
 
14406
+       while (hash_iterate(iter, &key, &value)) {
 
14407
+               struct managesieve_client *client = key;
 
14408
+
 
14409
+               client_destroy(client,  "Disconnected: Shutting down");
 
14410
+       }
 
14411
+       hash_iterate_deinit(iter);
 
14412
+}
 
14413
+
 
14414
+void clients_init(void)
 
14415
+{
 
14416
+       const char *str;
 
14417
+
 
14418
+       clients = hash_create(default_pool, default_pool, 128, NULL, NULL);
 
14419
+       to_idle = timeout_add(1000, idle_timeout, NULL);
 
14420
+
 
14421
+       /* Specific MANAGESIEVE settings */
 
14422
+       str = getenv("MANAGESIEVE_IMPLEMENTATION_STRING");
 
14423
+       managesieve_implementation_string = str != NULL ?
 
14424
+       str : DEFAULT_MANAGESIEVE_IMPLEMENTATION_STRING;
 
14425
+
 
14426
+       sieve_init();
 
14427
+       sieve_set_implementation("cmu");
 
14428
+}
 
14429
+
 
14430
+void clients_deinit(void)
 
14431
+{
 
14432
+       clients_destroy_all();
 
14433
+       hash_destroy(clients);
 
14434
+
 
14435
+       timeout_remove(&to_idle);
 
14436
+       sieve_deinit();
 
14437
+}
 
14438
diff -r 894f003d9f5f src/managesieve-login/client.h
 
14439
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
14440
+++ b/src/managesieve-login/client.h    Sun May 04 16:00:59 2008 +0200
 
14441
@@ -0,0 +1,72 @@
 
14442
+#ifndef __CLIENT_H
 
14443
+#define __CLIENT_H
 
14444
+
 
14445
+#include "network.h"
 
14446
+#include "master.h"
 
14447
+#include "client-common.h"
 
14448
+
 
14449
+/* FIXME: Duplicate, also defined in src/managesieve */
 
14450
+#define DEFAULT_MANAGESIEVE_IMPLEMENTATION_STRING PACKAGE
 
14451
+
 
14452
+/* maximum length for MANAGESIEVE command line. */
 
14453
+#define MAX_MANAGESIEVE_LINE 8192
 
14454
+
 
14455
+struct managesieve_client {
 
14456
+       struct client common;
 
14457
+
 
14458
+       time_t created;
 
14459
+       int refcount;
 
14460
+
 
14461
+       struct io *io;
 
14462
+       struct istream *input;
 
14463
+       struct ostream *output;
 
14464
+       struct managesieve_parser *parser;
 
14465
+
 
14466
+       struct login_proxy *proxy;
 
14467
+       char *proxy_user, *proxy_password;
 
14468
+
 
14469
+       time_t last_input;
 
14470
+       unsigned int bad_counter;
 
14471
+
 
14472
+       const char *cmd_name;
 
14473
+
 
14474
+       unsigned int cmd_finished:1;
 
14475
+       unsigned int skip_line:1;
 
14476
+       unsigned int input_blocked:1;
 
14477
+       unsigned int destroyed:1;
 
14478
+       unsigned int greeting_sent:1;
 
14479
+
 
14480
+       /* Maybe these should be combined in some enum state variable */
 
14481
+       unsigned int proxy_greeting_recvd:1;  
 
14482
+       unsigned int proxy_login_sent:1;
 
14483
+};
 
14484
+
 
14485
+void client_destroy(struct managesieve_client *client, const char *reason);
 
14486
+void client_destroy_internal_failure(struct managesieve_client *client);
 
14487
+
 
14488
+void client_send_line(struct managesieve_client *client, const char *line);
 
14489
+
 
14490
+bool client_read(struct managesieve_client *client);
 
14491
+bool client_skip_line(struct managesieve_client *client);
 
14492
+void client_input(void *context);
 
14493
+
 
14494
+void client_ref(struct managesieve_client *client);
 
14495
+bool client_unref(struct managesieve_client *client);
 
14496
+
 
14497
+void _client_send_response(struct managesieve_client *client,
 
14498
+  const char *oknobye, const char *resp_code, const char *msg);
 
14499
+
 
14500
+#define client_send_ok(client, msg) \
 
14501
+       _client_send_response(client, "OK", NULL, msg)
 
14502
+#define client_send_no(client, msg) \
 
14503
+  _client_send_response(client, "NO", NULL, msg)
 
14504
+#define client_send_bye(client, msg) \
 
14505
+  _client_send_response(client, "BYE", NULL, msg)
 
14506
+
 
14507
+#define client_send_okresp(client, resp_code, msg) \
 
14508
+  _client_send_response(client, "OK", resp_code, msg)
 
14509
+#define client_send_noresp(client, resp_code, msg) \
 
14510
+  _client_send_response(client, "NO", resp_code, msg)
 
14511
+#define client_send_byeresp(client, resp_code, msg) \
 
14512
+  _client_send_response(client, "BYE", resp_code, msg)
 
14513
+#endif
 
14514
diff -r 894f003d9f5f src/managesieve-login/managesieve-proxy.c
 
14515
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
14516
+++ b/src/managesieve-login/managesieve-proxy.c Sun May 04 16:00:59 2008 +0200
 
14517
@@ -0,0 +1,299 @@
 
14518
+/* Copyright (C) 2004 Timo Sirainen */
 
14519
+
 
14520
+#include <string.h>
 
14521
+#include "common.h"
 
14522
+#include "ioloop.h"
 
14523
+#include "istream.h"
 
14524
+#include "ostream.h"
 
14525
+#include "str.h"
 
14526
+#include "safe-memset.h"
 
14527
+#include "buffer.h"
 
14528
+#include "base64.h"
 
14529
+#include "client.h"
 
14530
+#include "managesieve-quote.h"
 
14531
+#include "managesieve-proxy.h"
 
14532
+#include "managesieve-parser.h"
 
14533
+
 
14534
+static int proxy_input_line(struct managesieve_client *client,
 
14535
+                           struct ostream *output, const char *line)
 
14536
+{
 
14537
+       string_t *str;
 
14538
+       const char *msg;
 
14539
+
 
14540
+       i_assert(!client->destroyed);
 
14541
+
 
14542
+       if (!client->proxy_login_sent) {
 
14543
+               string_t *plain_login, *base64;
 
14544
+               struct istream *input;
 
14545
+               struct managesieve_parser *parser;
 
14546
+               struct managesieve_arg *args;
 
14547
+               int ret;
 
14548
+               bool fatal = FALSE, greeting_recvd = FALSE;
 
14549
+
 
14550
+               /* Server will send greeting which is actually a capability 
 
14551
+                * response. Output from a faulty server should not be accepted,
 
14552
+                * so the response is parsed and verified.
 
14553
+                */
 
14554
+
 
14555
+               /* Build an input stream for the managesieve parser 
 
14556
+                *  FIXME: It would be nice if the line-wise parsing could be
 
14557
+                *    substituded by something similar to the command line interpreter.
 
14558
+                *    However, the current login_proxy structure does not make streams
 
14559
+                *    known until inside proxi_input handler.
 
14560
+                */
 
14561
+               line = t_strconcat(line, "\r\n", NULL);
 
14562
+               input = i_stream_create_from_data(pool_datastack_create(), line,
 
14563
+                       strlen(line));
 
14564
+               parser = managesieve_parser_create(input, NULL, MAX_MANAGESIEVE_LINE);
 
14565
+               managesieve_parser_reset(parser);
 
14566
+
 
14567
+           /* Parse input 
 
14568
+                *  FIXME: Theoretically the OK response could include a 
 
14569
+                *   response code which could be rejected by the parser. 
 
14570
+                */ 
 
14571
+               (void)i_stream_read(input);
 
14572
+               ret = managesieve_parser_read_args(parser, 2, 0, &args);
 
14573
+               
 
14574
+               if ( ret >= 1 ) {
 
14575
+                       if ( args[0].type == MANAGESIEVE_ARG_ATOM &&
 
14576
+                       strncasecmp(MANAGESIEVE_ARG_STR(&(args[0])), "OK", 2) == 0 ) {
 
14577
+
 
14578
+                               /* Received OK response; greeting is finished */
 
14579
+                               greeting_recvd = TRUE;
 
14580
+
 
14581
+               } else if ( args[0].type == MANAGESIEVE_ARG_STRING ) {
 
14582
+                       if ( strncasecmp(MANAGESIEVE_ARG_STR(&(args[0])), "SASL", 4) == 0 ) {
 
14583
+                                       /* Check whether the server supports the SASL mechanism 
 
14584
+                                * we are going to use (currently only PLAIN supported). 
 
14585
+                                        */
 
14586
+                                       if ( ret == 2 && args[1].type == MANAGESIEVE_ARG_STRING ) {
 
14587
+                                               char *p = MANAGESIEVE_ARG_STR(&(args[1]));
 
14588
+                                               int mech_found = FALSE;
 
14589
+                                                               
 
14590
+                                               while ( p != NULL ) {
 
14591
+                                                       if ( strncasecmp(p, "PLAIN", 5) == 0 ) {
 
14592
+                                                               mech_found = TRUE;
 
14593
+                                                               break;
 
14594
+                                       }
 
14595
+
 
14596
+                                                       p = strchr(p, ' ');
 
14597
+                                                       if ( p != NULL ) p++;
 
14598
+                                               }        
 
14599
+
 
14600
+                                               if ( !mech_found ) {
 
14601
+                                                       i_error("managesieve-proxy(%s): "
 
14602
+                                                       "Server does not support required PLAIN SASL mechanism.",
 
14603
+                                                       client->common.virtual_user);
 
14604
+
 
14605
+                                                       fatal = TRUE;
 
14606
+                                               }       
 
14607
+                                       }
 
14608
+                               }       
 
14609
+                       } else {
 
14610
+                               /* Do not accept faulty server */
 
14611
+                       i_error("managesieve-proxy(%s): "
 
14612
+                               "Remote returned with invalid capability/greeting line: %s",
 
14613
+                               client->common.virtual_user, line);
 
14614
+
 
14615
+                               fatal = TRUE;
 
14616
+                       }
 
14617
+
 
14618
+       } else if ( ret == -2 ) {
 
14619
+                       /* Parser needs more data (not possible on mem stream) */
 
14620
+                       i_unreached();
 
14621
+
 
14622
+       } else if ( ret < 0 ) {
 
14623
+                       const char *error_str = managesieve_parser_get_error(parser, &fatal);
 
14624
+                       error_str = (error_str != NULL ? error_str : "unknown (bug)" );
 
14625
+       
 
14626
+                       /* Do not accept faulty server */
 
14627
+                       i_error("managesieve-proxy(%s): "
 
14628
+                       "Protocol parse error(%d) in capability/greeting line: %s (line='%s')",
 
14629
+                       client->common.virtual_user, ret, error_str, line);
 
14630
+       
 
14631
+                       fatal = TRUE;
 
14632
+               }
 
14633
+
 
14634
+               /* Cleanup parser */
 
14635
+       managesieve_parser_destroy(&parser);
 
14636
+           i_stream_destroy(&input);
 
14637
+
 
14638
+               /* Time to exit if greeting was not accepted */
 
14639
+               if ( fatal ) {                  
 
14640
+                       client_destroy_internal_failure(client);
 
14641
+       
 
14642
+                       return -1;
 
14643
+               }
 
14644
+
 
14645
+               /* Wait until greeting is received completely */
 
14646
+               if ( !greeting_recvd ) return 0;
 
14647
+
 
14648
+               /* Send AUTHENTICATE "PLAIN" command 
 
14649
+        *  FIXME: Currently there seems to be no SASL client implementation,
 
14650
+                *    so only implement the trivial PLAIN method 
 
14651
+                *    - Stephan
 
14652
+            */
 
14653
+               t_push();
 
14654
+       
 
14655
+               /*   Base64-encode the credentials 
 
14656
+                *         [authorization ID \0 authentication ID \0 pass]
 
14657
+            */
 
14658
+               plain_login = buffer_create_dynamic(pool_datastack_create(), 64);
 
14659
+               buffer_append_c(plain_login, '\0');
 
14660
+               buffer_append(plain_login, client->proxy_user, strlen(client->proxy_user));
 
14661
+               buffer_append_c(plain_login, '\0');
 
14662
+               buffer_append(plain_login, client->proxy_password, strlen(client->proxy_password));
 
14663
+
 
14664
+               base64 = buffer_create_dynamic(pool_datastack_create(),
 
14665
+               MAX_BASE64_ENCODED_SIZE(plain_login->used));
 
14666
+               base64_encode(plain_login->data, plain_login->used, base64);
 
14667
+
 
14668
+               /*   Send command */
 
14669
+               str = t_str_new(128);
 
14670
+               str_append(str, "AUTHENTICATE \"PLAIN\" ");
 
14671
+               managesieve_quote_append_string(str, str_c(base64),  FALSE);
 
14672
+               str_append(str, "\r\n");
 
14673
+               (void)o_stream_send(output, str_data(str), str_len(str));
 
14674
+               
 
14675
+               /*   Cleanup */
 
14676
+               t_pop();
 
14677
+
 
14678
+               /* Cleanup sensitive data */
 
14679
+               safe_memset(client->proxy_password, 0,
 
14680
+                          strlen(client->proxy_password));
 
14681
+               i_free(client->proxy_password);
 
14682
+               client->proxy_password = NULL;
 
14683
+               client->proxy_login_sent = TRUE;
 
14684
+
 
14685
+               return 0;
 
14686
+
 
14687
+       } else { 
 
14688
+               if (strncasecmp(line, "OK ", 3) == 0) {
 
14689
+                       /* Login successful. Send this line to client. */
 
14690
+                       o_stream_cork(client->output);
 
14691
+                       (void)o_stream_send_str(client->output, line);
 
14692
+                       (void)o_stream_send(client->output, "\r\n", 2);
 
14693
+                       o_stream_uncork(client->output);
 
14694
+
 
14695
+                       msg = t_strdup_printf("managesieve-proxy(%s): started proxying to %s:%u",
 
14696
+                                     client->common.virtual_user,
 
14697
+                                     login_proxy_get_host(client->proxy),
 
14698
+                                     login_proxy_get_port(client->proxy));
 
14699
+
 
14700
+                       (void)client_skip_line(client);
 
14701
+                       login_proxy_detach(client->proxy, client->input,
 
14702
+                                  client->output);
 
14703
+
 
14704
+                       client->proxy = NULL;
 
14705
+                       client->input = NULL;
 
14706
+                       client->output = NULL;
 
14707
+                       client->common.fd = -1;
 
14708
+                       client_destroy(client, msg);
 
14709
+
 
14710
+               } else {
 
14711
+                       /* Login failed. Send our own failure reply so client can't
 
14712
+                        * figure out if user exists or not just by looking at the
 
14713
+                        * reply string.
 
14714
+                        */
 
14715
+                       client_send_no(client, AUTH_FAILED_MSG);
 
14716
+
 
14717
+                       /* allow client input again */
 
14718
+                       i_assert(client->io == NULL);
 
14719
+                       client->io = io_add(client->common.fd, IO_READ,
 
14720
+                                   client_input, client);
 
14721
+
 
14722
+                       login_proxy_free(client->proxy);
 
14723
+                       client->proxy = NULL;
 
14724
+
 
14725
+                       i_free(client->proxy_user);
 
14726
+                       client->proxy_user = NULL;
 
14727
+               }
 
14728
+
 
14729
+               return -1;
 
14730
+       }
 
14731
+
 
14732
+       i_unreached();
 
14733
+       return -1;
 
14734
+}
 
14735
+
 
14736
+static void proxy_input(struct istream *input, struct ostream *output,
 
14737
+                       void *context)
 
14738
+{
 
14739
+       struct managesieve_client *client = context;
 
14740
+       const char *line;
 
14741
+
 
14742
+       if (input == NULL) {
 
14743
+               if (client->io != NULL) {
 
14744
+                       /* remote authentication failed, we're just
 
14745
+                          freeing the proxy */
 
14746
+                       return;
 
14747
+               }
 
14748
+
 
14749
+               if (client->destroyed) {
 
14750
+                       /* we came here from client_destroy() */
 
14751
+                       return;
 
14752
+               }
 
14753
+
 
14754
+               /* failed for some reason, probably server disconnected */
 
14755
+               client_send_byeresp(client, "TRYLATER", "Temporary login failure.");
 
14756
+               client_destroy(client, NULL);
 
14757
+               return;
 
14758
+       }
 
14759
+
 
14760
+       i_assert(!client->destroyed);
 
14761
+
 
14762
+       switch (i_stream_read(input)) {
 
14763
+       case -2:
 
14764
+               /* buffer full */
 
14765
+               i_error("managesieve-proxy(%s): Remote input buffer full",
 
14766
+                       client->common.virtual_user);
 
14767
+               client_destroy_internal_failure(client);
 
14768
+               return;
 
14769
+       case -1:
 
14770
+               /* disconnected */
 
14771
+               client_destroy(client, "Proxy: Remote disconnected");
 
14772
+               return;
 
14773
+       }
 
14774
+
 
14775
+       while ((line = i_stream_next_line(input)) != NULL) {
 
14776
+               if (proxy_input_line(client, output, line) < 0)
 
14777
+                       break;
 
14778
+       }
 
14779
+}
 
14780
+
 
14781
+int managesieve_proxy_new(struct managesieve_client *client, const char *host,
 
14782
+                  unsigned int port, const char *user, const char *password)
 
14783
+{
 
14784
+       i_assert(user != NULL);
 
14785
+       i_assert(!client->destroyed);
 
14786
+
 
14787
+       if (password == NULL) {
 
14788
+               i_error("proxy(%s): password not given",
 
14789
+                       client->common.virtual_user);
 
14790
+               return -1;
 
14791
+       }
 
14792
+
 
14793
+       i_assert(client->refcount > 1);
 
14794
+       connection_queue_add(1);
 
14795
+
 
14796
+       if (client->destroyed) {
 
14797
+               /* connection_queue_add() decided that we were the oldest
 
14798
+                  connection and killed us. */
 
14799
+               return -1;
 
14800
+       }
 
14801
+
 
14802
+       client->proxy = login_proxy_new(&client->common, host, port,
 
14803
+                                       proxy_input, client);
 
14804
+       if (client->proxy == NULL)
 
14805
+               return -1;
 
14806
+
 
14807
+       client->proxy_login_sent = FALSE;
 
14808
+       client->proxy_user = i_strdup(user);
 
14809
+       client->proxy_password = i_strdup(password);
 
14810
+
 
14811
+       /* disable input until authentication is finished */
 
14812
+       if (client->io != NULL)
 
14813
+               io_remove(&client->io);
 
14814
+
 
14815
+       return 0;
 
14816
+}
 
14817
diff -r 894f003d9f5f src/managesieve-login/managesieve-proxy.h
 
14818
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
14819
+++ b/src/managesieve-login/managesieve-proxy.h Sun May 04 16:00:59 2008 +0200
 
14820
@@ -0,0 +1,9 @@
 
14821
+#ifndef __MANAGESIEVE_PROXY_H
 
14822
+#define __MANAGESIEVE_PROXY_H
 
14823
+
 
14824
+#include "login-proxy.h"
 
14825
+
 
14826
+int managesieve_proxy_new(struct managesieve_client *client, const char *host,
 
14827
+                  unsigned int port, const char *user, const char *password);
 
14828
+
 
14829
+#endif
 
14830
diff -r 894f003d9f5f src/managesieve/Makefile.am
 
14831
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
14832
+++ b/src/managesieve/Makefile.am       Sun May 04 16:00:59 2008 +0200
 
14833
@@ -0,0 +1,56 @@
 
14834
+pkglibexecdir = $(libexecdir)/dovecot
 
14835
+
 
14836
+pkglibexec_PROGRAMS = managesieve
 
14837
+
 
14838
+AM_CPPFLAGS = \
 
14839
+       -I$(top_srcdir)/src/lib \
 
14840
+       -I$(top_srcdir)/src/lib-dict \
 
14841
+       -I$(top_srcdir)/src/lib-managesieve \
 
14842
+       -DMODULEDIR=\""$(moduledir)"\" \
 
14843
+       -I$(top_srcdir)/src/lib-sievestorage \
 
14844
+       -I$(top_srcdir)/src/lib-sieve
 
14845
+
 
14846
+managesieve_LDFLAGS = -export-dynamic
 
14847
+
 
14848
+# get some functions included which only plugins use. liblib should probably
 
14849
+# be a shared library so this wouldn't be needed..
 
14850
+unused_objects = \
 
14851
+       ../lib/mountpoint.o 
 
14852
+
 
14853
+libs = \
 
14854
+       ../lib-managesieve/libmanagesieve.a \
 
14855
+  ../lib-sievestorage/libsievestorage.a \
 
14856
+       ../lib-sieve/libsieve.la \
 
14857
+       ../lib-dict/libdict.a \
 
14858
+       ../lib-charset/libcharset.a \
 
14859
+       ../lib/liblib.a \
 
14860
+       $(unused_objects) 
 
14861
+
 
14862
+managesieve_LDADD = \
 
14863
+       $(libs) \
 
14864
+       $(LIBICONV) \
 
14865
+       $(RAND_LIBS) \
 
14866
+       $(MODULE_LIBS) 
 
14867
+
 
14868
+managesieve_DEPENDENCIES = $(libs)
 
14869
+
 
14870
+cmds = \
 
14871
+       cmd-capability.c \
 
14872
+       cmd-logout.c \
 
14873
+       cmd-putscript.c \
 
14874
+       cmd-getscript.c \
 
14875
+       cmd-setactive.c \
 
14876
+       cmd-deletescript.c \
 
14877
+       cmd-listscripts.c \
 
14878
+       cmd-havespace.c 
 
14879
+
 
14880
+managesieve_SOURCES = \
 
14881
+       $(cmds) \
 
14882
+       client.c \
 
14883
+       commands.c \
 
14884
+       main.c 
 
14885
+
 
14886
+noinst_HEADERS = \
 
14887
+       client.h \
 
14888
+       commands.h \
 
14889
+       common.h 
 
14890
diff -r 894f003d9f5f src/managesieve/client.c
 
14891
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
14892
+++ b/src/managesieve/client.c  Sun May 04 16:00:59 2008 +0200
 
14893
@@ -0,0 +1,541 @@
 
14894
+#include "common.h"
 
14895
+#include "str.h"
 
14896
+#include "ioloop.h"
 
14897
+#include "network.h"
 
14898
+#include "istream.h"
 
14899
+#include "ostream.h"
 
14900
+#include "commands.h"
 
14901
+
 
14902
+#include "managesieve-quote.h"
 
14903
+#include "sieve-storage.h"
 
14904
+#include "sieve-implementation.h"
 
14905
+
 
14906
+#include "client.h"
 
14907
+
 
14908
+#include <stdlib.h>
 
14909
+#include <unistd.h>
 
14910
+
 
14911
+static struct client *my_client; /* we don't need more than one currently */
 
14912
+static struct timeout *to_idle;
 
14913
+
 
14914
+struct client *client_create(int fd_in, int fd_out, struct sieve_storage *storage)
 
14915
+{
 
14916
+       struct client *client;
 
14917
+
 
14918
+       /* always use nonblocking I/O */
 
14919
+       net_set_nonblock(fd_in, TRUE);
 
14920
+       net_set_nonblock(fd_out, TRUE);
 
14921
+
 
14922
+       client = i_new(struct client, 1);
 
14923
+       client->fd_in = fd_in;
 
14924
+       client->fd_out = fd_out;
 
14925
+       client->input = i_stream_create_file(fd_in, default_pool,
 
14926
+                                            managesieve_max_line_length, FALSE);
 
14927
+       client->output = o_stream_create_file(fd_out, default_pool,
 
14928
+                                             (size_t)-1, FALSE);
 
14929
+
 
14930
+       o_stream_set_flush_callback(client->output, _client_output, client);
 
14931
+
 
14932
+       client->io = io_add(fd_in, IO_READ, _client_input, client);
 
14933
+       client->parser = managesieve_parser_create(client->input, client->output,
 
14934
+                                           managesieve_max_line_length);
 
14935
+       client->last_input = ioloop_time;
 
14936
+
 
14937
+       client->cmd.pool = pool_alloconly_create("command pool", 8192);
 
14938
+       client->cmd.client = client;
 
14939
+
 
14940
+       client->storage = storage;
 
14941
+
 
14942
+       i_assert(my_client == NULL);
 
14943
+       my_client = client;
 
14944
+
 
14945
+       if (hook_client_created != NULL)
 
14946
+               hook_client_created(&client);
 
14947
+       return client;
 
14948
+}
 
14949
+
 
14950
+static const char *client_get_disconnect_reason(struct client *client)
 
14951
+{
 
14952
+       errno = client->input->stream_errno != 0 ?
 
14953
+               client->input->stream_errno :
 
14954
+               client->output->stream_errno;
 
14955
+       return errno == 0 || errno == EPIPE ? "Connection closed" :
 
14956
+               t_strdup_printf("Connection closed: %m");
 
14957
+}
 
14958
+
 
14959
+void client_destroy(struct client *client, const char *reason)
 
14960
+{
 
14961
+       int ret;
 
14962
+
 
14963
+       i_assert(!client->handling_input);
 
14964
+       i_assert(!client->destroyed);
 
14965
+       client->destroyed = TRUE;
 
14966
+
 
14967
+       if (!client->disconnected) {
 
14968
+               client->disconnected = TRUE;
 
14969
+               if (reason == NULL)
 
14970
+                       reason = client_get_disconnect_reason(client);
 
14971
+               i_info("%s", reason);
 
14972
+       }
 
14973
+
 
14974
+       if (client->command_pending) {
 
14975
+               /* try to deinitialize the command */
 
14976
+               i_assert(client->cmd.func != NULL);
 
14977
+               i_stream_close(client->input);
 
14978
+               o_stream_close(client->output);
 
14979
+               client->input_pending = FALSE;
 
14980
+
 
14981
+               ret = client->cmd.func(&client->cmd);
 
14982
+               i_assert(ret);
 
14983
+       }
 
14984
+
 
14985
+       managesieve_parser_destroy(&client->parser);
 
14986
+       if (client->io != NULL)
 
14987
+               io_remove(&client->io);
 
14988
+
 
14989
+       i_stream_destroy(&client->input);
 
14990
+       o_stream_destroy(&client->output);
 
14991
+
 
14992
+       if (close(client->fd_in) < 0)
 
14993
+               i_error("close(client in) failed: %m");
 
14994
+       if (client->fd_in != client->fd_out) {
 
14995
+               if (close(client->fd_out) < 0)
 
14996
+                       i_error("close(client out) failed: %m");
 
14997
+       }
 
14998
+
 
14999
+       pool_unref(client->cmd.pool);
 
15000
+       i_free(client);
 
15001
+
 
15002
+       /* quit the program */
 
15003
+       my_client = NULL;
 
15004
+       io_loop_stop(ioloop);
 
15005
+}
 
15006
+
 
15007
+void client_disconnect(struct client *client, const char *reason)
 
15008
+{
 
15009
+       i_assert(reason != NULL);
 
15010
+
 
15011
+       if (client->disconnected)
 
15012
+               return;
 
15013
+
 
15014
+       i_info("Disconnected: %s", reason);
 
15015
+       client->disconnected = TRUE;
 
15016
+       (void)o_stream_flush(client->output);
 
15017
+
 
15018
+       i_stream_close(client->input);
 
15019
+       o_stream_close(client->output);
 
15020
+}
 
15021
+
 
15022
+void client_disconnect_with_error(struct client *client, const char *msg)
 
15023
+{
 
15024
+       client_send_bye(client, msg);
 
15025
+       client_disconnect(client, msg);
 
15026
+}
 
15027
+
 
15028
+int client_send_line(struct client *client, const char *data) 
 
15029
+{
 
15030
+       struct const_iovec iov[2];
 
15031
+
 
15032
+       if (client->output->closed)
 
15033
+               return -1;
 
15034
+
 
15035
+       iov[0].iov_base = data;
 
15036
+       iov[0].iov_len = strlen(data);
 
15037
+       iov[1].iov_base = "\r\n";
 
15038
+       iov[1].iov_len = 2;
 
15039
+
 
15040
+       if (o_stream_sendv(client->output, iov, 2) < 0)
 
15041
+               return -1;
 
15042
+       client->last_output = ioloop_time;
 
15043
+
 
15044
+       if (o_stream_get_buffer_used_size(client->output) >=
 
15045
+           CLIENT_OUTPUT_OPTIMAL_SIZE) {
 
15046
+               /* buffer full, try flushing */
 
15047
+               return o_stream_flush(client->output);
 
15048
+       }
 
15049
+       return 1;
 
15050
+}
 
15051
+
 
15052
+void client_send_response(struct client *client,
 
15053
+  const char *oknobye, const char *resp_code, const char *msg)
 
15054
+{
 
15055
+       string_t *str;
 
15056
+       
 
15057
+       str = t_str_new(128);
 
15058
+       str_append(str, oknobye);
 
15059
+
 
15060
+       if ( resp_code != NULL ) {
 
15061
+               str_append(str, " (");
 
15062
+               str_append(str, resp_code);
 
15063
+               str_append_c(str, ')');
 
15064
+       }
 
15065
+
 
15066
+       if ( msg != NULL ) {
 
15067
+               str_append_c(str, ' ');
 
15068
+               managesieve_quote_append_string(str, msg, TRUE);
 
15069
+       }
 
15070
+
 
15071
+       client_send_line(client, str_c(str));
 
15072
+}
 
15073
+
 
15074
+void client_send_command_error(struct client_command_context *cmd,
 
15075
+                              const char *msg)
 
15076
+{
 
15077
+       struct client *client = cmd->client;
 
15078
+       const char *error, *cmd_name;
 
15079
+       bool fatal;
 
15080
+
 
15081
+       if (msg == NULL) {
 
15082
+               msg = managesieve_parser_get_error(client->parser, &fatal);
 
15083
+               if (fatal) {
 
15084
+                       client_disconnect_with_error(client, msg);
 
15085
+                       return;
 
15086
+               }
 
15087
+       }
 
15088
+
 
15089
+       if (cmd->name == NULL)
 
15090
+               error = t_strconcat
 
15091
+                       ("Error in MANAGESIEVE command: ", msg, NULL);
 
15092
+       else {
 
15093
+               cmd_name = t_str_ucase(cmd->name);
 
15094
+               error = t_strconcat
 
15095
+                       ("Error in MANAGESIEVE command ", cmd_name, ": ", msg, NULL);
 
15096
+       }
 
15097
+
 
15098
+       client_send_no(client, error);
 
15099
+
 
15100
+       if (++client->bad_counter >= CLIENT_MAX_BAD_COMMANDS) {
 
15101
+               client_disconnect_with_error(client,
 
15102
+                       "Too many invalid MANAGESIEVE commands.");
 
15103
+       }
 
15104
+
 
15105
+       /* client_read_args() failures rely on this being set, so that the
 
15106
+          command processing is stopped even while command function returns
 
15107
+          FALSE. */
 
15108
+       cmd->param_error = TRUE;
 
15109
+}
 
15110
+
 
15111
+void client_send_storage_error(struct client *client,
 
15112
+             struct sieve_storage *storage)
 
15113
+{
 
15114
+  const char *error;
 
15115
+
 
15116
+  error = sieve_storage_get_last_error(storage);
 
15117
+
 
15118
+  client_send_no(client, error);
 
15119
+}
 
15120
+
 
15121
+void client_send_sieve_error(struct client *client)
 
15122
+{
 
15123
+  const char *error;
 
15124
+
 
15125
+  error = sieve_get_last_error();
 
15126
+
 
15127
+  client_send_no(client, error);
 
15128
+}
 
15129
+
 
15130
+bool client_read_args(struct client_command_context *cmd, unsigned int count,
 
15131
+                     unsigned int flags, struct managesieve_arg **args)
 
15132
+{
 
15133
+       int ret;
 
15134
+
 
15135
+       i_assert(count <= INT_MAX);
 
15136
+
 
15137
+       ret = managesieve_parser_read_args(cmd->client->parser, count, flags, args);
 
15138
+       if (ret >= (int)count) {
 
15139
+               /* all parameters read successfully */
 
15140
+               return TRUE;
 
15141
+       } else if (ret == -2) {
 
15142
+               /* need more data */
 
15143
+               return FALSE;
 
15144
+       } else {
 
15145
+               /* error, or missing arguments */
 
15146
+               client_send_command_error(cmd, ret < 0 ? NULL :
 
15147
+                                         "Missing arguments");
 
15148
+               return FALSE;
 
15149
+       }
 
15150
+}
 
15151
+
 
15152
+bool client_read_string_args(struct client_command_context *cmd,
 
15153
+                            unsigned int count, ...)
 
15154
+{
 
15155
+       struct managesieve_arg *managesieve_args;
 
15156
+       va_list va;
 
15157
+       const char *str;
 
15158
+       unsigned int i;
 
15159
+
 
15160
+       if (!client_read_args(cmd, count, 0, &managesieve_args))
 
15161
+               return FALSE;
 
15162
+
 
15163
+       va_start(va, count);
 
15164
+       for (i = 0; i < count; i++) {
 
15165
+               const char **ret = va_arg(va, const char **);
 
15166
+
 
15167
+               if (managesieve_args[i].type == MANAGESIEVE_ARG_EOL) {
 
15168
+                       client_send_command_error(cmd, "Missing arguments.");
 
15169
+                       break;
 
15170
+               }
 
15171
+
 
15172
+               str = managesieve_arg_string(&managesieve_args[i]);
 
15173
+               if (str == NULL) {
 
15174
+                       client_send_command_error(cmd, "Invalid arguments.");
 
15175
+                       break;
 
15176
+               }
 
15177
+
 
15178
+               if (ret != NULL)
 
15179
+                       *ret = str;
 
15180
+       }
 
15181
+       va_end(va);
 
15182
+
 
15183
+       return i == count;
 
15184
+}
 
15185
+
 
15186
+void _client_reset_command(struct client *client)
 
15187
+{
 
15188
+       pool_t pool;
 
15189
+       size_t size;
 
15190
+
 
15191
+       /* reset input idle time because command output might have taken a
 
15192
+          long time and we don't want to disconnect client immediately then */
 
15193
+       client->last_input = ioloop_time;
 
15194
+
 
15195
+       client->command_pending = FALSE;
 
15196
+    if (client->io == NULL && !client->disconnected) {
 
15197
+        i_assert(i_stream_get_fd(client->input) >= 0);
 
15198
+        client->io = io_add(i_stream_get_fd(client->input),
 
15199
+                    IO_READ, _client_input, client);
 
15200
+    }
 
15201
+    o_stream_set_flush_callback(client->output, _client_output, client);
 
15202
+
 
15203
+       pool = client->cmd.pool;
 
15204
+       memset(&client->cmd, 0, sizeof(client->cmd));
 
15205
+
 
15206
+       p_clear(pool);
 
15207
+       client->cmd.pool = pool;
 
15208
+       client->cmd.client = client;
 
15209
+
 
15210
+       managesieve_parser_reset(client->parser);
 
15211
+
 
15212
+       /* if there's unread data in buffer, remember that there's input
 
15213
+          pending and we should get around to calling client_input() soon.
 
15214
+          This is mostly for APPEND/IDLE. */
 
15215
+       (void)i_stream_get_data(client->input, &size);
 
15216
+       if (size > 0 && !client->destroyed)
 
15217
+               client->input_pending = TRUE;
 
15218
+}
 
15219
+
 
15220
+/* Skip incoming data until newline is found,
 
15221
+   returns TRUE if newline was found. */
 
15222
+static bool client_skip_line(struct client *client)
 
15223
+{
 
15224
+       const unsigned char *data;
 
15225
+       size_t i, data_size;
 
15226
+
 
15227
+       data = i_stream_get_data(client->input, &data_size);
 
15228
+
 
15229
+       for (i = 0; i < data_size; i++) {
 
15230
+               if (data[i] == '\n') {
 
15231
+                       client->input_skip_line = FALSE;
 
15232
+                       i++;
 
15233
+                       break;
 
15234
+               }
 
15235
+       }
 
15236
+
 
15237
+       i_stream_skip(client->input, i);
 
15238
+       return !client->input_skip_line;
 
15239
+}
 
15240
+
 
15241
+static bool client_handle_input(struct client_command_context *cmd)
 
15242
+{
 
15243
+       struct client *client = cmd->client;
 
15244
+
 
15245
+       if (cmd->func != NULL) {
 
15246
+               /* command is being executed - continue it */
 
15247
+               if (cmd->func(cmd) || cmd->param_error) {
 
15248
+                       /* command execution was finished */
 
15249
+                       if (!cmd->param_error)
 
15250
+                               client->bad_counter = 0;
 
15251
+                       _client_reset_command(client);
 
15252
+                       return TRUE;
 
15253
+               }
 
15254
+
 
15255
+               /* unfinished */
 
15256
+        if (client->command_pending)
 
15257
+            o_stream_set_flush_pending(client->output, TRUE);
 
15258
+               return FALSE;
 
15259
+       }
 
15260
+
 
15261
+       if (client->input_skip_line) {
 
15262
+               /* we're just waiting for new line.. */
 
15263
+               if (!client_skip_line(client))
 
15264
+                       return FALSE;
 
15265
+
 
15266
+               /* got the newline */
 
15267
+               _client_reset_command(client);
 
15268
+
 
15269
+               /* pass through to parse next command */
 
15270
+       }
 
15271
+
 
15272
+       if (cmd->name == NULL) {
 
15273
+               cmd->name = managesieve_parser_read_word(client->parser);
 
15274
+               if (cmd->name == NULL)
 
15275
+                       return FALSE; /* need more data */
 
15276
+               cmd->name = p_strdup(cmd->pool, cmd->name);
 
15277
+       }
 
15278
+
 
15279
+       if (cmd->name == '\0') {
 
15280
+               /* command not given - cmd_func is already NULL. */
 
15281
+       } else {
 
15282
+               /* find the command function */
 
15283
+               cmd->func = command_find(cmd->name);
 
15284
+       }
 
15285
+
 
15286
+       client->input_skip_line = TRUE;
 
15287
+       if (cmd->func == NULL) {
 
15288
+               /* unknown command */
 
15289
+               client_send_command_error(cmd, "Unknown command.");
 
15290
+               _client_reset_command(client);
 
15291
+       } else {
 
15292
+               i_assert(!client->disconnected);
 
15293
+
 
15294
+               client_handle_input(cmd);
 
15295
+       }
 
15296
+
 
15297
+       return TRUE;
 
15298
+}
 
15299
+
 
15300
+void _client_input(void *context)
 
15301
+{
 
15302
+       struct client *client = context;
 
15303
+       struct client_command_context *cmd = &client->cmd;
 
15304
+       int ret;
 
15305
+
 
15306
+       if (client->command_pending) {
 
15307
+               /* already processing one command. wait. */
 
15308
+               io_remove(&client->io);
 
15309
+               return;
 
15310
+       }
 
15311
+
 
15312
+       client->input_pending = FALSE;
 
15313
+       client->last_input = ioloop_time;
 
15314
+
 
15315
+       switch (i_stream_read(client->input)) {
 
15316
+       case -1:
 
15317
+               /* disconnected */
 
15318
+               client_destroy(client, NULL);
 
15319
+               return;
 
15320
+       case -2:
 
15321
+               /* parameter word is longer than max. input buffer size.
 
15322
+                  this is most likely an error, so skip the new data
 
15323
+                  until newline is found. */
 
15324
+               client->input_skip_line = TRUE;
 
15325
+
 
15326
+               client_send_command_error(cmd, "Too long argument.");
 
15327
+               _client_reset_command(client);
 
15328
+               break;
 
15329
+       }
 
15330
+
 
15331
+       client->handling_input = TRUE;
 
15332
+       o_stream_cork(client->output);
 
15333
+       do {
 
15334
+               t_push();
 
15335
+               ret = client_handle_input(cmd);
 
15336
+               t_pop();
 
15337
+       } while (ret && !client->disconnected);
 
15338
+    o_stream_uncork(client->output);
 
15339
+    client->handling_input = FALSE;
 
15340
+
 
15341
+       if (client->command_pending)
 
15342
+               client->input_pending = TRUE;
 
15343
+
 
15344
+       if (client->output->closed)
 
15345
+               client_destroy(client, NULL);
 
15346
+}
 
15347
+
 
15348
+int _client_output(void *context)
 
15349
+{
 
15350
+       struct client *client = context;
 
15351
+       struct client_command_context *cmd = &client->cmd;
 
15352
+       int ret;
 
15353
+       bool finished;
 
15354
+
 
15355
+       client->last_output = ioloop_time;
 
15356
+
 
15357
+       if ((ret = o_stream_flush(client->output)) < 0) {
 
15358
+               client_destroy(client, NULL);
 
15359
+               return 1;
 
15360
+       }
 
15361
+
 
15362
+       if (!client->command_pending)
 
15363
+               return 1;
 
15364
+
 
15365
+       /* continue processing command */
 
15366
+       o_stream_cork(client->output);
 
15367
+       client->output_pending = TRUE;
 
15368
+       finished = cmd->func(cmd) || cmd->param_error;
 
15369
+
 
15370
+       /* a bit kludgy check. normally we would want to get back to this
 
15371
+          output handler, but IDLE is a special case which has command
 
15372
+          pending but without necessarily anything to write. */
 
15373
+       if (!finished && client->output_pending)
 
15374
+               o_stream_set_flush_pending(client->output, TRUE);
 
15375
+
 
15376
+       o_stream_uncork(client->output);
 
15377
+
 
15378
+       if (finished) {
 
15379
+               /* command execution was finished */
 
15380
+               client->bad_counter = 0;
 
15381
+               _client_reset_command(client);
 
15382
+
 
15383
+               if (client->input_pending)
 
15384
+                       _client_input(client);
 
15385
+       }
 
15386
+       return ret;
 
15387
+}
 
15388
+
 
15389
+static void idle_timeout(void *context __attr_unused__)
 
15390
+{
 
15391
+       time_t idle_time, last_change;
 
15392
+
 
15393
+       if (my_client == NULL)
 
15394
+               return;
 
15395
+
 
15396
+       /* We mostly want to check last_input here, but if there is a very long
 
15397
+          running command (like copying thousands of messages), we don't want
 
15398
+          to disconnect the client just after the command was finished.
 
15399
+          But any output that IDLE has sent should be ignored. */
 
15400
+       last_change = I_MAX(my_client->last_input, my_client->last_output);
 
15401
+       idle_time = ioloop_time - last_change;
 
15402
+
 
15403
+       if (my_client->command_pending &&
 
15404
+               o_stream_get_buffer_used_size(my_client->output) > 0 &&
 
15405
+               idle_time >= CLIENT_OUTPUT_TIMEOUT) {
 
15406
+        /* client isn't reading our output */
 
15407
+               client_destroy(my_client, "Disconnected for inactivity "
 
15408
+                   "in reading our output");
 
15409
+       } else if (idle_time >= CLIENT_IDLE_TIMEOUT) {
 
15410
+               /* client isn't sending us anything */
 
15411
+               if (!my_client->command_pending) {
 
15412
+                       client_send_bye(my_client,
 
15413
+                               "Disconnected for inactivity.");
 
15414
+               }
 
15415
+               client_destroy(my_client, "Disconnected for inactivity");
 
15416
+       }
 
15417
+}
 
15418
+
 
15419
+void clients_init(void)
 
15420
+{
 
15421
+       my_client = NULL;
 
15422
+       to_idle = timeout_add(10000, idle_timeout, NULL);
 
15423
+}
 
15424
+
 
15425
+void clients_deinit(void)
 
15426
+{
 
15427
+       if (my_client != NULL) {
 
15428
+               client_send_bye(my_client, "Server shutting down.");
 
15429
+               client_destroy(my_client, "Server shutting down");
 
15430
+       }
 
15431
+
 
15432
+       timeout_remove(&to_idle);
 
15433
+}
 
15434
+
 
15435
diff -r 894f003d9f5f src/managesieve/client.h
 
15436
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
15437
+++ b/src/managesieve/client.h  Sun May 04 16:00:59 2008 +0200
 
15438
@@ -0,0 +1,103 @@
 
15439
+#ifndef __CLIENT_H
 
15440
+#define __CLIENT_H
 
15441
+
 
15442
+#include "commands.h"
 
15443
+
 
15444
+struct client;
 
15445
+struct sieve_storage;
 
15446
+struct managesieve_parser;
 
15447
+struct managesieve_arg;
 
15448
+
 
15449
+struct client_command_context {
 
15450
+       struct client *client;
 
15451
+
 
15452
+       pool_t pool;
 
15453
+       const char *name;
 
15454
+
 
15455
+       command_func_t *func;
 
15456
+       void *context;
 
15457
+
 
15458
+       unsigned int param_error:1;
 
15459
+};
 
15460
+
 
15461
+struct client {
 
15462
+       int fd_in, fd_out;
 
15463
+       struct sieve_storage *storage;
 
15464
+
 
15465
+       struct io *io;
 
15466
+       struct istream *input;
 
15467
+       struct ostream *output;
 
15468
+
 
15469
+       time_t last_input, last_output;
 
15470
+       unsigned int bad_counter;
 
15471
+
 
15472
+       struct managesieve_parser *parser;
 
15473
+       struct client_command_context cmd;
 
15474
+
 
15475
+       unsigned int disconnected:1;
 
15476
+       unsigned int destroyed:1;
 
15477
+       unsigned int command_pending:1;
 
15478
+       unsigned int input_pending:1;
 
15479
+       unsigned int output_pending:1;
 
15480
+       unsigned int handling_input:1;
 
15481
+       unsigned int rawlog:1;
 
15482
+       unsigned int input_skip_line:1; /* skip all the data until we've
 
15483
+                                          found a new line */
 
15484
+};
 
15485
+
 
15486
+/* Create new client with specified input/output handles. socket specifies
 
15487
+   if the handle is a socket. */
 
15488
+struct client *client_create(int fd_in, int fd_out, struct sieve_storage *storage);
 
15489
+void client_destroy(struct client *client, const char *reason);
 
15490
+
 
15491
+/* Disconnect client connection */
 
15492
+void client_disconnect(struct client *client, const char *reason);
 
15493
+void client_disconnect_with_error(struct client *client, const char *msg);
 
15494
+
 
15495
+/* Send a line of data to client. Returns 1 if ok, 0 if buffer is getting full,
 
15496
+   -1 if error */
 
15497
+int client_send_line(struct client *client, const char *data);
 
15498
+
 
15499
+void client_send_response(struct client *client,
 
15500
+  const char *oknobye, const char *resp_code, const char *msg);
 
15501
+
 
15502
+#define client_send_ok(client, msg) \
 
15503
+  client_send_response(client, "OK", NULL, msg)
 
15504
+#define client_send_no(client, msg) \
 
15505
+  client_send_response(client, "NO", NULL, msg)
 
15506
+#define client_send_bye(client, msg) \
 
15507
+  client_send_response(client, "BYE", NULL, msg)
 
15508
+
 
15509
+#define client_send_okresp(client, resp_code, msg) \
 
15510
+  client_send_response(client, "OK", resp_code, msg)
 
15511
+#define client_send_noresp(client, resp_code, msg) \
 
15512
+  client_send_response(client, "NO", resp_code, msg)
 
15513
+#define client_send_byeresp(cmd, resp_code, msg) \
 
15514
+  client_send_response(client, "BYE", resp_code, msg)
 
15515
+
 
15516
+/* Send BAD command error to client. msg can be NULL. */
 
15517
+void client_send_command_error(struct client_command_context *cmd,
 
15518
+                              const char *msg);
 
15519
+
 
15520
+/* Send storage or sieve related errors to the client */
 
15521
+void client_send_storage_error(struct client *client,
 
15522
+             struct sieve_storage *storage);
 
15523
+void client_send_sieve_error(struct client *client);
 
15524
+
 
15525
+/* Read a number of arguments. Returns TRUE if everything was read or
 
15526
+   FALSE if either needs more data or error occurred. */
 
15527
+bool client_read_args(struct client_command_context *cmd, unsigned int count,
 
15528
+                     unsigned int flags, struct managesieve_arg **args);
 
15529
+/* Reads a number of string arguments. ... is a list of pointers where to
 
15530
+   store the arguments. */
 
15531
+bool client_read_string_args(struct client_command_context *cmd,
 
15532
+                            unsigned int count, ...);
 
15533
+
 
15534
+void clients_init(void);
 
15535
+void clients_deinit(void);
 
15536
+
 
15537
+void _client_reset_command(struct client *client);
 
15538
+void _client_input(void *context);
 
15539
+int _client_output(void *context);
 
15540
+
 
15541
+#endif
 
15542
diff -r 894f003d9f5f src/managesieve/cmd-capability.c
 
15543
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
15544
+++ b/src/managesieve/cmd-capability.c  Sun May 04 16:00:59 2008 +0200
 
15545
@@ -0,0 +1,30 @@
 
15546
+#include "common.h"
 
15547
+#include "commands.h"
 
15548
+#include "str.h"
 
15549
+#include "strfuncs.h"
 
15550
+#include "ostream.h"
 
15551
+#include "sieve-implementation.h"
 
15552
+
 
15553
+bool cmd_capability(struct client_command_context *cmd)
 
15554
+{
 
15555
+       struct client *client = cmd->client;
 
15556
+       const char *sievecap, *sieveimpl;
 
15557
+
 
15558
+       sievecap = sieve_get_capabilities();
 
15559
+       if (sievecap == NULL)
 
15560
+               sievecap = "";
 
15561
+
 
15562
+       t_push();               
 
15563
+       sievecap = t_strconcat("\"SIEVE\" \"", sievecap, "\"", NULL);
 
15564
+       sieveimpl = t_strconcat("\"IMPLEMENTATION\" \"", 
 
15565
+    managesieve_implementation_string, "\"", NULL);
 
15566
+
 
15567
+       client_send_line(client, sieveimpl);
 
15568
+       client_send_line(client, sievecap);
 
15569
+       client_send_line(client, "OK \"Capability completed.\"");
 
15570
+       t_pop();
 
15571
+
 
15572
+       return TRUE;
 
15573
+
 
15574
+}
 
15575
+
 
15576
diff -r 894f003d9f5f src/managesieve/cmd-deletescript.c
 
15577
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
15578
+++ b/src/managesieve/cmd-deletescript.c        Sun May 04 16:00:59 2008 +0200
 
15579
@@ -0,0 +1,40 @@
 
15580
+#include "common.h"
 
15581
+#include "commands.h"
 
15582
+
 
15583
+#include "sieve-script.h"
 
15584
+
 
15585
+bool cmd_deletescript(struct client_command_context *cmd)
 
15586
+{
 
15587
+       struct client *client = cmd->client;
 
15588
+       struct sieve_storage *storage = client->storage;
 
15589
+       const char *scriptname;
 
15590
+       struct sieve_script *script;
 
15591
+       bool exists;
 
15592
+
 
15593
+       /* <scrip name>*/
 
15594
+       if (!client_read_string_args(cmd, 1, &scriptname))
 
15595
+               return FALSE;
 
15596
+
 
15597
+       exists = TRUE;
 
15598
+       script = sieve_script_init(storage, scriptname, &exists);
 
15599
+
 
15600
+       if (script == NULL) {
 
15601
+               if (!exists) 
 
15602
+                       client_send_no(client, "Script does not exist.");
 
15603
+               else 
 
15604
+                       client_send_storage_error(client, storage);
 
15605
+
 
15606
+               return TRUE;
 
15607
+       }
 
15608
+
 
15609
+       if (sieve_script_delete(&script) < 0)
 
15610
+               client_send_storage_error(client, storage);
 
15611
+       else
 
15612
+               client_send_ok(client, "Deletescript completed.");
 
15613
+
 
15614
+       /* Script object is deleted no matter what in 
 
15615
+        * sieve_script_delete()
 
15616
+        */
 
15617
+
 
15618
+       return TRUE;
 
15619
+}
 
15620
diff -r 894f003d9f5f src/managesieve/cmd-getscript.c
 
15621
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
15622
+++ b/src/managesieve/cmd-getscript.c   Sun May 04 16:00:59 2008 +0200
 
15623
@@ -0,0 +1,122 @@
 
15624
+#include "common.h"
 
15625
+#include "ostream.h"
 
15626
+#include "commands.h"
 
15627
+#include "istream.h"
 
15628
+#include "sieve-script.h"
 
15629
+
 
15630
+struct cmd_getscript_context {
 
15631
+       struct client *client;
 
15632
+       struct client_command_context *cmd;
 
15633
+       struct sieve_storage *storage;  
 
15634
+       uoff_t scriptsize;
 
15635
+
 
15636
+       struct sieve_script *script;
 
15637
+       struct istream *scriptstream;
 
15638
+       bool failed;
 
15639
+       bool exists;
 
15640
+};
 
15641
+
 
15642
+static bool cmd_getscript_finish(struct cmd_getscript_context *ctx)
 
15643
+{
 
15644
+  struct client *client = ctx->client;
 
15645
+
 
15646
+       if (ctx->script != NULL)
 
15647
+               sieve_script_unref(&ctx->script);
 
15648
+
 
15649
+       if (ctx->failed) {
 
15650
+               if (client->output->closed) {
 
15651
+                       client_disconnect(client, "Disconnected");
 
15652
+                       return TRUE;
 
15653
+               }
 
15654
+
 
15655
+               if (!ctx->exists) {
 
15656
+                       client_send_no(client, "Script does not exist.");
 
15657
+                       return TRUE;
 
15658
+               }
 
15659
+               
 
15660
+               client_send_storage_error(client, client->storage);
 
15661
+               return TRUE;
 
15662
+       }
 
15663
+
 
15664
+       client_send_line(client, "");
 
15665
+       client_send_ok(client, "Getscript completed.");
 
15666
+       return TRUE;
 
15667
+}
 
15668
+
 
15669
+static bool cmd_getscript_continue(struct client_command_context *cmd)
 
15670
+{
 
15671
+       struct client *client = cmd->client;
 
15672
+       struct cmd_getscript_context *ctx = cmd->context;
 
15673
+
 
15674
+       if (o_stream_send_istream(client->output, ctx->scriptstream) < 0) {
 
15675
+               sieve_storage_set_critical(ctx->storage,
 
15676
+                       "o_stream_send_istream(%s) failed: %m", sieve_script_name(ctx->script));
 
15677
+               ctx->failed = TRUE;    
 
15678
+       }
 
15679
+
 
15680
+       /* FIXME: Check whether there is a bug in the io_stream_sendfile function
 
15681
+        * as the eof indicator of the input stream is never set. The stream_sendfile
 
15682
+        * function does not use read functions of the inputstream and therefore
 
15683
+        * the eof indicator will not be updated. Workaround: check v_offset == size 
 
15684
+        * as well.
 
15685
+        */
 
15686
+       if (ctx->scriptstream->eof || ctx->scriptstream->closed ||
 
15687
+               ctx->scriptstream->v_offset == ctx->scriptsize ) {
 
15688
+               if (client->output->closed || ctx->scriptstream->v_offset < ctx->scriptsize) 
 
15689
+                       ctx->failed = TRUE;
 
15690
+       } else if (!ctx->failed) 
 
15691
+               /* unfinished */
 
15692
+               return FALSE;
 
15693
+
 
15694
+       return cmd_getscript_finish(ctx);
 
15695
+}
 
15696
+
 
15697
+bool cmd_getscript(struct client_command_context *cmd)
 
15698
+{
 
15699
+       struct client *client = cmd->client;
 
15700
+       struct cmd_getscript_context *ctx;
 
15701
+       const char *scriptname;
 
15702
+       int ret;
 
15703
+       bool deleted_r;
 
15704
+
 
15705
+       /* <scriptname> */
 
15706
+       if (!client_read_string_args(cmd, 1, &scriptname))
 
15707
+               return FALSE;
 
15708
+
 
15709
+       ctx = p_new(cmd->pool, struct cmd_getscript_context, 1);
 
15710
+       ctx->cmd = cmd;
 
15711
+       ctx->client = client;
 
15712
+       ctx->storage = client->storage;
 
15713
+       ctx->failed = FALSE;
 
15714
+       
 
15715
+       ctx->exists = TRUE;
 
15716
+       ctx->script = sieve_script_init(client->storage, scriptname, &ctx->exists);
 
15717
+
 
15718
+       if (ctx->script == NULL) {
 
15719
+               ctx->failed = TRUE;
 
15720
+               return cmd_getscript_finish(ctx);
 
15721
+       }
 
15722
+                       
 
15723
+       ctx->scriptstream = sieve_script_open(ctx->script, &deleted_r);
 
15724
+
 
15725
+       if ( ctx->scriptstream == NULL ) {
 
15726
+               ctx->failed = TRUE;
 
15727
+               ctx->exists = !deleted_r;
 
15728
+               return cmd_getscript_finish(ctx);
 
15729
+       }
 
15730
+
 
15731
+       ctx->scriptsize = 0;
 
15732
+       if ( (ret=sieve_script_get_size(ctx->script, &ctx->scriptsize)) <= 0 ) {
 
15733
+               ctx->failed = TRUE;
 
15734
+               ctx->exists = (ret < 0);
 
15735
+               return cmd_getscript_finish(ctx);
 
15736
+       }
 
15737
+
 
15738
+       client_send_line(client, t_strdup_printf("{%"PRIuUOFF_T"}", ctx->scriptsize));
 
15739
+
 
15740
+       client->command_pending = TRUE;
 
15741
+       cmd->func = cmd_getscript_continue;
 
15742
+       cmd->context = ctx;
 
15743
+
 
15744
+       return cmd_getscript_continue(cmd);
 
15745
+}
 
15746
diff -r 894f003d9f5f src/managesieve/cmd-havespace.c
 
15747
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
15748
+++ b/src/managesieve/cmd-havespace.c   Sun May 04 16:00:59 2008 +0200
 
15749
@@ -0,0 +1,38 @@
 
15750
+#include "common.h"
 
15751
+#include "commands.h"
 
15752
+
 
15753
+bool cmd_havespace(struct client_command_context *cmd)
 
15754
+{
 
15755
+  struct client *client = cmd->client;
 
15756
+       struct managesieve_arg *args;
 
15757
+       const char *scriptname;
 
15758
+       uoff_t size;
 
15759
+       int ret;
 
15760
+
 
15761
+       /* <scriptname> <size> */
 
15762
+       if (!(ret=client_read_args(cmd, 2, 0, &args)))
 
15763
+         return FALSE;
 
15764
+
 
15765
+       if ( ret > 2 ) {
 
15766
+               client_send_no(client, "Too many arguments");
 
15767
+               return TRUE;
 
15768
+       }
 
15769
+
 
15770
+       if ( (scriptname = managesieve_arg_string(&args[0])) == NULL ) {
 
15771
+               client_send_no(client, "Invalid string for scriptname.");
 
15772
+               return TRUE;
 
15773
+       }
 
15774
+
 
15775
+       if ( managesieve_arg_number(&args[1], &size) < 0 ) {
 
15776
+               client_send_no(client, "Invalid scriptsize argument.");
 
15777
+               return TRUE;
 
15778
+       }
 
15779
+
 
15780
+       if ( size == 0 ) {
 
15781
+               client_send_no(client, "Cannot upload empty script.");
 
15782
+               return TRUE;
 
15783
+       }
 
15784
+
 
15785
+       client_send_ok(client, "Putscript would succeed.");
 
15786
+       return TRUE;
 
15787
+}
 
15788
diff -r 894f003d9f5f src/managesieve/cmd-listscripts.c
 
15789
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
15790
+++ b/src/managesieve/cmd-listscripts.c Sun May 04 16:00:59 2008 +0200
 
15791
@@ -0,0 +1,46 @@
 
15792
+#include "common.h"
 
15793
+#include "commands.h"
 
15794
+#include "str.h"
 
15795
+#include "sieve-storage.h"
 
15796
+#include "sieve-list.h"
 
15797
+#include "managesieve-quote.h"
 
15798
+
 
15799
+bool cmd_listscripts(struct client_command_context *cmd)
 
15800
+{
 
15801
+  struct client *client = cmd->client;
 
15802
+       struct sieve_list_context *ctx;
 
15803
+       const char *scriptname;
 
15804
+       bool active;
 
15805
+       string_t *str;
 
15806
+
 
15807
+       if ( (ctx = sieve_storage_list_init(client->storage))
 
15808
+               == NULL ) {
 
15809
+               client_send_storage_error(client, client->storage);
 
15810
+               return TRUE;
 
15811
+       }
 
15812
+
 
15813
+       /* FIXME: This will be quite slow for large script lists. Implement
 
15814
+        * some buffering to fix this. Wont truely be an issue with managesieve
 
15815
+        * though.
 
15816
+        */
 
15817
+       while ((scriptname = sieve_storage_list_next(ctx, &active)) != NULL) {
 
15818
+               t_push();
 
15819
+               str = t_str_new(128);
 
15820
+         
 
15821
+               managesieve_quote_append_string(str, scriptname, FALSE);
 
15822
+               
 
15823
+               if ( active ) 
 
15824
+                 str_append(str, " ACTIVE");
 
15825
+               
 
15826
+               client_send_line(client, str_c(str));
 
15827
+               t_pop();
 
15828
+       }
 
15829
+  
 
15830
+       if ( sieve_storage_list_deinit(&ctx) < 0 ) {
 
15831
+               client_send_storage_error(client, client->storage);
 
15832
+               return TRUE;
 
15833
+       }
 
15834
+       
 
15835
+       client_send_ok(client, "Listscripts completed.");
 
15836
+       return TRUE;
 
15837
+}
 
15838
diff -r 894f003d9f5f src/managesieve/cmd-logout.c
 
15839
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
15840
+++ b/src/managesieve/cmd-logout.c      Sun May 04 16:00:59 2008 +0200
 
15841
@@ -0,0 +1,12 @@
 
15842
+#include "common.h"
 
15843
+#include "ostream.h"
 
15844
+#include "commands.h"
 
15845
+
 
15846
+bool cmd_logout(struct client_command_context *cmd)
 
15847
+{
 
15848
+       struct client *client = cmd->client;
 
15849
+
 
15850
+       client_send_line(client, "OK \"Logout completed.\"");
 
15851
+       client_disconnect(client, "Logged out");
 
15852
+       return TRUE;
 
15853
+}
 
15854
diff -r 894f003d9f5f src/managesieve/cmd-putscript.c
 
15855
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
15856
+++ b/src/managesieve/cmd-putscript.c   Sun May 04 16:00:59 2008 +0200
 
15857
@@ -0,0 +1,355 @@
 
15858
+#include "common.h"
 
15859
+#include "ioloop.h"
 
15860
+#include "istream.h"
 
15861
+#include "ostream.h"
 
15862
+#include "str.h"
 
15863
+#include "commands.h"
 
15864
+#include "managesieve-parser.h"
 
15865
+#include "sieve-storage.h"
 
15866
+#include "sieve-save.h"
 
15867
+#include "sieve-implementation.h"
 
15868
+
 
15869
+#include <sys/time.h>
 
15870
+
 
15871
+struct cmd_putscript_context {
 
15872
+       struct client *client;
 
15873
+       struct client_command_context *cmd;
 
15874
+       struct sieve_storage *storage;
 
15875
+
 
15876
+       struct istream *input;
 
15877
+
 
15878
+       const char *scriptname;
 
15879
+       uoff_t script_size;     
 
15880
+
 
15881
+       struct managesieve_parser *save_parser;
 
15882
+       struct sieve_save_context *save_ctx;
 
15883
+};
 
15884
+
 
15885
+static void cmd_putscript_finish(struct cmd_putscript_context *ctx);
 
15886
+static bool cmd_putscript_continue_script(struct client_command_context *cmd);
 
15887
+
 
15888
+static void client_input(void *context)
 
15889
+{
 
15890
+       struct client *client = context;
 
15891
+       struct client_command_context *cmd = &client->cmd;
 
15892
+
 
15893
+       client->last_input = ioloop_time;
 
15894
+
 
15895
+       switch (i_stream_read(client->input)) {
 
15896
+       case -1:
 
15897
+               /* disconnected */
 
15898
+               cmd_putscript_finish(cmd->context);
 
15899
+               /* Reset command so that client_destroy() doesn't try to call
 
15900
+                  cmd_putscript_continue_script() anymore. */
 
15901
+               _client_reset_command(client);
 
15902
+               client_destroy(client, "Disconnected in putscript");
 
15903
+               return;
 
15904
+       case -2:
 
15905
+               cmd_putscript_finish(cmd->context);
 
15906
+               if (client->command_pending) {
 
15907
+                       /* message data, this is handled internally by
 
15908
+                          mailbox_save_continue() */
 
15909
+                       break;
 
15910
+               }
 
15911
+
 
15912
+               /* parameter word is longer than max. input buffer size.
 
15913
+                  this is most likely an error, so skip the new data
 
15914
+                  until newline is found. */
 
15915
+               client->input_skip_line = TRUE;
 
15916
+
 
15917
+               client_send_command_error(cmd, "Too long argument.");
 
15918
+               _client_reset_command(client);
 
15919
+               return;
 
15920
+       }
 
15921
+
 
15922
+       if (cmd->func(cmd)) {
 
15923
+               /* command execution was finished. Note that if cmd_sync()
 
15924
+                  didn't finish, we didn't get here but the input handler
 
15925
+                  has already been moved. So don't do anything important
 
15926
+                  here..
 
15927
+
 
15928
+                  reset command once again to reset cmd_sync()'s changes. */
 
15929
+               _client_reset_command(client);
 
15930
+
 
15931
+               if (client->input_pending)
 
15932
+                       _client_input(client);
 
15933
+       }
 
15934
+}
 
15935
+
 
15936
+static void cmd_putscript_finish(struct cmd_putscript_context *ctx)
 
15937
+{
 
15938
+       io_remove(&ctx->client->io);
 
15939
+
 
15940
+       managesieve_parser_destroy(&ctx->save_parser);
 
15941
+
 
15942
+       if (ctx->input != NULL)
 
15943
+               i_stream_unref(&ctx->input);
 
15944
+
 
15945
+       if (ctx->save_ctx != NULL)
 
15946
+       {
 
15947
+               ctx->client->input_skip_line = TRUE;
 
15948
+               sieve_storage_save_abort(ctx->save_ctx);
 
15949
+       }
 
15950
+
 
15951
+       ctx->client->bad_counter = 0;
 
15952
+       o_stream_set_flush_callback(ctx->client->output,
 
15953
+                                   _client_output, ctx->client);
 
15954
+}
 
15955
+
 
15956
+static bool cmd_putscript_continue_cancel(struct client_command_context *cmd)
 
15957
+{
 
15958
+       struct cmd_putscript_context *ctx = cmd->context;
 
15959
+       size_t size;
 
15960
+
 
15961
+       (void)i_stream_read(ctx->input);
 
15962
+       (void)i_stream_get_data(ctx->input, &size);
 
15963
+       i_stream_skip(ctx->input, size);
 
15964
+
 
15965
+       if (ctx->input->v_offset == ctx->script_size ||
 
15966
+           cmd->client->input->closed) {
 
15967
+               cmd_putscript_finish(ctx);
 
15968
+               return TRUE;
 
15969
+       }
 
15970
+       return FALSE;
 
15971
+}
 
15972
+
 
15973
+static bool cmd_putscript_cancel(struct cmd_putscript_context *ctx, bool nonsync)
 
15974
+{
 
15975
+       ctx->client->input_skip_line = TRUE;
 
15976
+
 
15977
+       if (!nonsync) {
 
15978
+               cmd_putscript_finish(ctx);
 
15979
+               return TRUE;
 
15980
+       }
 
15981
+
 
15982
+       /* we have to read the nonsynced literal so we don't treat the message
 
15983
+          data as commands. */
 
15984
+       ctx->input = i_stream_create_limit(default_pool, ctx->client->input,
 
15985
+                                          ctx->client->input->v_offset,
 
15986
+                                          ctx->script_size);
 
15987
+
 
15988
+       ctx->client->command_pending = TRUE;
 
15989
+       ctx->cmd->func = cmd_putscript_continue_cancel;
 
15990
+       ctx->cmd->context = ctx;
 
15991
+       return cmd_putscript_continue_cancel(ctx->cmd);
 
15992
+}
 
15993
+
 
15994
+static bool cmd_putscript_finish_parsing(struct client_command_context *cmd)
 
15995
+{
 
15996
+       struct client *client = cmd->client;
 
15997
+       struct cmd_putscript_context *ctx = cmd->context;
 
15998
+       struct managesieve_arg *args;
 
15999
+       struct sieve_script *script;
 
16000
+       int ret;
 
16001
+       
 
16002
+       /* if error occurs, the CRLF is already read. */
 
16003
+       client->input_skip_line = FALSE;
 
16004
+       
 
16005
+       /* <script literal> */
 
16006
+       ret = managesieve_parser_read_args(ctx->save_parser, 0,
 
16007
+          MANAGESIEVE_PARSE_FLAG_LITERAL_SIZE, &args);
 
16008
+
 
16009
+       if (ret == -1) {
 
16010
+               if (ctx->storage != NULL)
 
16011
+                       client_send_command_error(cmd, NULL);
 
16012
+               cmd_putscript_finish(ctx);
 
16013
+               return TRUE;
 
16014
+       }
 
16015
+       if (ret < 0) {
 
16016
+               /* need more data */
 
16017
+               return FALSE;
 
16018
+       }
 
16019
+
 
16020
+       if (args[0].type == MANAGESIEVE_ARG_EOL) {
 
16021
+               /* last message */
 
16022
+         /* eat away the trailing CRLF */
 
16023
+               client->input_skip_line = TRUE;
 
16024
+
 
16025
+               script = sieve_storage_save_get_tempscript
 
16026
+               (ctx->save_ctx);
 
16027
+
 
16028
+               if ( script == NULL || (sieve_compile(script, TRUE) < 0)) {
 
16029
+                       client_send_sieve_error(client);
 
16030
+                       cmd_putscript_finish(ctx);
 
16031
+                       return TRUE;
 
16032
+               } else {
 
16033
+                       ret = sieve_storage_save_commit(ctx->save_ctx);
 
16034
+                       if (ret < 0) {
 
16035
+                               client_send_storage_error(client, ctx->storage);
 
16036
+                               cmd_putscript_finish(ctx);
 
16037
+                               return TRUE;
 
16038
+                       } else 
 
16039
+                               ctx->save_ctx = NULL;
 
16040
+               }
 
16041
+         
 
16042
+               cmd_putscript_finish(ctx);
 
16043
+               client_send_ok(client, "Putscript completed.");
 
16044
+               
 
16045
+               return TRUE;
 
16046
+       }
 
16047
+
 
16048
+       client_send_command_error(cmd, "Too many command arguments.");
 
16049
+       cmd_putscript_finish(ctx);
 
16050
+       return TRUE;
 
16051
+}
 
16052
+
 
16053
+static bool cmd_putscript_continue_parsing(struct client_command_context *cmd)
 
16054
+{
 
16055
+       struct client *client = cmd->client;
 
16056
+       struct cmd_putscript_context *ctx = cmd->context;
 
16057
+       struct managesieve_arg *args;
 
16058
+       bool nonsync = FALSE;
 
16059
+       int ret;
 
16060
+
 
16061
+       /* if error occurs, the CRLF is already read. */
 
16062
+       client->input_skip_line = FALSE;
 
16063
+
 
16064
+       /* <script literal> */
 
16065
+       ret = managesieve_parser_read_args(ctx->save_parser, 0,
 
16066
+                                   MANAGESIEVE_PARSE_FLAG_LITERAL_SIZE, &args);
 
16067
+       if (ret == -1) {
 
16068
+               cmd_putscript_finish(ctx);
 
16069
+               client_send_command_error(cmd, "Invalid arguments.");
 
16070
+               client->input_skip_line = TRUE;
 
16071
+               return TRUE;
 
16072
+       }
 
16073
+       if (ret < 0) {
 
16074
+               /* need more data */
 
16075
+               return FALSE;
 
16076
+       }
 
16077
+
 
16078
+       if (args->type != MANAGESIEVE_ARG_STRING) {
 
16079
+               /* Validate the script argument */
 
16080
+               if (args->type != MANAGESIEVE_ARG_LITERAL_SIZE ) {
 
16081
+                       client_send_command_error(cmd, "Invalid arguments.");
 
16082
+                       return cmd_putscript_cancel(ctx, FALSE);
 
16083
+               }
 
16084
+
 
16085
+               ctx->script_size = MANAGESIEVE_ARG_LITERAL_SIZE(args);
 
16086
+               nonsync = TRUE;
 
16087
+       } else {
 
16088
+               /* FIXME */
 
16089
+               client_send_no(client, "This MANAGESIEVE implementation currently does not allow "
 
16090
+                              "quoted strings to be used for script contents.");
 
16091
+               return cmd_putscript_cancel(ctx, FALSE);                
 
16092
+       }
 
16093
+
 
16094
+       if (ctx->script_size == 0) {
 
16095
+               /* no message data, abort */
 
16096
+               client_send_no(client, "PUTSCRIPT aborted (no message data).");
 
16097
+               cmd_putscript_finish(ctx);
 
16098
+               return TRUE;
 
16099
+       }
 
16100
+
 
16101
+       /* save the script */
 
16102
+       ctx->input = i_stream_create_limit(default_pool, client->input,
 
16103
+                                          client->input->v_offset,
 
16104
+                                          ctx->script_size);
 
16105
+       ctx->save_ctx = sieve_storage_save_init(ctx->storage, ctx->scriptname, ctx->input);
 
16106
+
 
16107
+       if ( ctx->save_ctx == NULL ) {
 
16108
+               /* save initialization failed */
 
16109
+               client_send_storage_error(client, ctx->storage);
 
16110
+               return cmd_putscript_cancel(ctx, nonsync);
 
16111
+       }
 
16112
+
 
16113
+       /* after literal comes CRLF, if we fail make sure we eat it away */
 
16114
+       client->input_skip_line = TRUE;
 
16115
+
 
16116
+       client->command_pending = TRUE;
 
16117
+       cmd->func = cmd_putscript_continue_script;
 
16118
+       return cmd_putscript_continue_script(cmd);
 
16119
+}
 
16120
+
 
16121
+static bool cmd_putscript_continue_script(struct client_command_context *cmd)
 
16122
+{
 
16123
+       struct client *client = cmd->client;
 
16124
+       struct cmd_putscript_context *ctx = cmd->context;
 
16125
+       size_t size;
 
16126
+       bool failed;
 
16127
+
 
16128
+       if (ctx->save_ctx != NULL) {
 
16129
+               if (sieve_storage_save_continue(ctx->save_ctx) < 0) {
 
16130
+                       /* we still have to finish reading the script
 
16131
+                          from client */
 
16132
+                       sieve_storage_save_abort(ctx->save_ctx);
 
16133
+                       ctx->save_ctx = NULL;
 
16134
+               }
 
16135
+       }
 
16136
+
 
16137
+       if (ctx->save_ctx == NULL) {
 
16138
+               (void)i_stream_read(ctx->input);
 
16139
+               (void)i_stream_get_data(ctx->input, &size);
 
16140
+               i_stream_skip(ctx->input, size);
 
16141
+       }
 
16142
+
 
16143
+       if (ctx->input->eof || client->input->closed) {
 
16144
+               /* finished */
 
16145
+               bool all_written = ctx->input->v_offset == ctx->script_size;
 
16146
+
 
16147
+               i_stream_unref(&ctx->input);
 
16148
+               ctx->input = NULL;
 
16149
+
 
16150
+               if (ctx->save_ctx == NULL) {
 
16151
+                       /* failed above */
 
16152
+                       client_send_storage_error(client, ctx->storage);
 
16153
+                       failed = TRUE;
 
16154
+               } else if (!all_written) {
 
16155
+                       /* client disconnected before it finished sending the
 
16156
+                          whole message. */
 
16157
+                       failed = TRUE;
 
16158
+                       sieve_storage_save_abort(ctx->save_ctx);
 
16159
+               } else if (sieve_storage_save_finish(ctx->save_ctx) < 0) {
 
16160
+                       failed = TRUE;
 
16161
+                       client_send_storage_error(client, ctx->storage);
 
16162
+               } else {
 
16163
+                       failed = client->input->closed;
 
16164
+               }
 
16165
+
 
16166
+               if (failed) {
 
16167
+                       cmd_putscript_finish(ctx);
 
16168
+                       return TRUE;
 
16169
+               }
 
16170
+
 
16171
+               /* prepare for next message */
 
16172
+               client->command_pending = FALSE;
 
16173
+               managesieve_parser_reset(ctx->save_parser);
 
16174
+               cmd->func = cmd_putscript_finish_parsing;
 
16175
+               return cmd_putscript_finish_parsing(cmd);
 
16176
+       }
 
16177
+
 
16178
+       return FALSE;
 
16179
+}
 
16180
+
 
16181
+bool cmd_putscript(struct client_command_context *cmd)
 
16182
+{
 
16183
+       struct client *client = cmd->client;
 
16184
+       struct cmd_putscript_context *ctx;
 
16185
+       const char *scriptname;
 
16186
+
 
16187
+       /* <scriptname> */
 
16188
+       if (!client_read_string_args(cmd, 1, &scriptname) || 
 
16189
+               *scriptname == '\0')
 
16190
+               return FALSE;
 
16191
+
 
16192
+       ctx = p_new(cmd->pool, struct cmd_putscript_context, 1);
 
16193
+       ctx->cmd = cmd;
 
16194
+       ctx->client = client;
 
16195
+       ctx->storage = client->storage;
 
16196
+       ctx->scriptname = scriptname;
 
16197
+
 
16198
+       io_remove(&client->io);
 
16199
+       client->io = io_add(i_stream_get_fd(client->input), IO_READ,
 
16200
+                           client_input, client);
 
16201
+       /* putscript is special because we're only waiting on client input, not
 
16202
+          client output, so disable the standard output handler until we're
 
16203
+          finished */
 
16204
+       o_stream_set_flush_callback(client->output, NULL, NULL);
 
16205
+
 
16206
+       ctx->save_parser = managesieve_parser_create(client->input, client->output,
 
16207
+                                             managesieve_max_line_length);
 
16208
+
 
16209
+       cmd->func = cmd_putscript_continue_parsing;
 
16210
+       cmd->context = ctx;
 
16211
+       return cmd_putscript_continue_parsing(cmd);
 
16212
+}
 
16213
diff -r 894f003d9f5f src/managesieve/cmd-setactive.c
 
16214
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
16215
+++ b/src/managesieve/cmd-setactive.c   Sun May 04 16:00:59 2008 +0200
 
16216
@@ -0,0 +1,53 @@
 
16217
+#include "common.h"
 
16218
+#include "commands.h"
 
16219
+
 
16220
+#include "sieve-script.h"
 
16221
+
 
16222
+bool cmd_setactive(struct client_command_context *cmd)
 
16223
+{
 
16224
+       struct client *client = cmd->client;
 
16225
+       struct sieve_storage *storage = client->storage;
 
16226
+       const char *scriptname;
 
16227
+       struct sieve_script *script;
 
16228
+       bool exists;
 
16229
+       int ret;
 
16230
+
 
16231
+       /* <scriptname> */
 
16232
+       if (!client_read_string_args(cmd, 1, &scriptname))
 
16233
+               return FALSE;
 
16234
+
 
16235
+       if ( *scriptname != '\0' ) {
 
16236
+               exists = TRUE;
 
16237
+               script = sieve_script_init(storage, scriptname, &exists);
 
16238
+
 
16239
+               if (script == NULL) {
 
16240
+                       if (!exists)
 
16241
+                               client_send_no(client, "Script does not exist.");
 
16242
+                       else
 
16243
+                               client_send_storage_error(client, storage);
 
16244
+
 
16245
+                       return TRUE;
 
16246
+               }
 
16247
+       
 
16248
+               ret = sieve_script_activate(script);
 
16249
+               if ( ret < 0 )
 
16250
+                       client_send_storage_error(client, storage);
 
16251
+               else
 
16252
+                       client_send_ok(client, ret ? 
 
16253
+                               "Setactive completed." :
 
16254
+                               "Script is already active.");
 
16255
+
 
16256
+               sieve_script_unref(&script);
 
16257
+       } else {
 
16258
+               ret = sieve_storage_deactivate(storage);
 
16259
+               
 
16260
+               if ( ret < 0 )
 
16261
+                       client_send_storage_error(client, storage);
 
16262
+               else
 
16263
+                       client_send_ok(client, ret ?
 
16264
+                               "Active script is now deactivated." :
 
16265
+                               "No scripts currently active.");        
 
16266
+       }
 
16267
+
 
16268
+       return TRUE;
 
16269
+}
 
16270
diff -r 894f003d9f5f src/managesieve/commands.c
 
16271
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
16272
+++ b/src/managesieve/commands.c        Sun May 04 16:00:59 2008 +0200
 
16273
@@ -0,0 +1,112 @@
 
16274
+#include "common.h"
 
16275
+#include "array.h"
 
16276
+#include "commands.h"
 
16277
+
 
16278
+#include <stdlib.h>
 
16279
+
 
16280
+/* Might want to combine this somewhere in a commands-common.c 
 
16281
+ * to avoid duplicate code 
 
16282
+ */
 
16283
+
 
16284
+const struct command managesieve_commands[] = {
 
16285
+       { "CAPABILITY", cmd_capability },
 
16286
+       { "LOGOUT", cmd_logout },
 
16287
+       { "PUTSCRIPT", cmd_putscript },
 
16288
+       { "GETSCRIPT", cmd_getscript },
 
16289
+       { "SETACTIVE", cmd_setactive },
 
16290
+       { "DELETESCRIPT", cmd_deletescript },
 
16291
+       { "LISTSCRIPTS", cmd_listscripts },
 
16292
+       { "HAVESPACE", cmd_havespace }
 
16293
+};
 
16294
+
 
16295
+#define MANAGESIEVE_COMMANDS_COUNT \
 
16296
+       (sizeof(managesieve_commands) / sizeof(managesieve_commands[0]))
 
16297
+
 
16298
+static array_t ARRAY_DEFINE(commands, struct command);
 
16299
+static bool commands_unsorted;
 
16300
+
 
16301
+void command_register(const char *name, command_func_t *func)
 
16302
+{
 
16303
+       struct command cmd;
 
16304
+
 
16305
+       cmd.name = name;
 
16306
+       cmd.func = func;
 
16307
+       array_append(&commands, &cmd, 1);
 
16308
+
 
16309
+       commands_unsorted = TRUE;
 
16310
+}
 
16311
+
 
16312
+void command_unregister(const char *name)
 
16313
+{
 
16314
+       const struct command *cmd;
 
16315
+       unsigned int i, count;
 
16316
+
 
16317
+       cmd = array_get(&commands, &count);
 
16318
+       for (i = 0; i < count; i++) {
 
16319
+               if (strcasecmp(cmd[i].name, name) == 0) {
 
16320
+                       array_delete(&commands, i, 1);
 
16321
+                       return;
 
16322
+               }
 
16323
+       }
 
16324
+
 
16325
+       i_error("Trying to unregister unknown command '%s'", name);
 
16326
+}
 
16327
+
 
16328
+void command_register_array(const struct command *cmdarr, unsigned int count)
 
16329
+{
 
16330
+       commands_unsorted = TRUE;
 
16331
+       array_append(&commands, cmdarr, count);
 
16332
+}
 
16333
+
 
16334
+void command_unregister_array(const struct command *cmdarr, unsigned int count)
 
16335
+{
 
16336
+       while (count > 0) {
 
16337
+               command_unregister(cmdarr->name);
 
16338
+               count--; cmdarr++;
 
16339
+       }
 
16340
+}
 
16341
+
 
16342
+static int command_cmp(const void *p1, const void *p2)
 
16343
+{
 
16344
+       const struct command *c1 = p1, *c2 = p2;
 
16345
+
 
16346
+       return strcasecmp(c1->name, c2->name);
 
16347
+}
 
16348
+
 
16349
+static int command_bsearch(const void *name, const void *cmd_p)
 
16350
+{
 
16351
+       const struct command *cmd = cmd_p;
 
16352
+
 
16353
+       return strcasecmp(name, cmd->name);
 
16354
+}
 
16355
+
 
16356
+command_func_t *command_find(const char *name)
 
16357
+{
 
16358
+       const struct command *cmd;
 
16359
+       void *base;
 
16360
+       unsigned int count;
 
16361
+
 
16362
+       base = array_get_modifyable(&commands, &count);
 
16363
+       if (commands_unsorted) {
 
16364
+               qsort(base, count, sizeof(struct command), command_cmp);
 
16365
+                           commands_unsorted = FALSE;
 
16366
+       }
 
16367
+
 
16368
+    cmd = bsearch(name, base, count, sizeof(struct command),
 
16369
+                    command_bsearch);
 
16370
+       return cmd == NULL ? NULL : cmd->func;
 
16371
+}
 
16372
+
 
16373
+void commands_init(void)
 
16374
+{
 
16375
+       ARRAY_CREATE(&commands, system_pool, struct command, 64);
 
16376
+    commands_unsorted = FALSE;
 
16377
+
 
16378
+       command_register_array(managesieve_commands, MANAGESIEVE_COMMANDS_COUNT);
 
16379
+}
 
16380
+
 
16381
+void commands_deinit(void)
 
16382
+{
 
16383
+       command_unregister_array(managesieve_commands, MANAGESIEVE_COMMANDS_COUNT);
 
16384
+       array_free(&commands);
 
16385
+}
 
16386
diff -r 894f003d9f5f src/managesieve/commands.h
 
16387
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
16388
+++ b/src/managesieve/commands.h        Sun May 04 16:00:59 2008 +0200
 
16389
@@ -0,0 +1,45 @@
 
16390
+#ifndef __COMMANDS_H
 
16391
+#define __COMMANDS_H
 
16392
+
 
16393
+struct client_command_context;
 
16394
+
 
16395
+#include "managesieve-parser.h"
 
16396
+
 
16397
+typedef bool command_func_t(struct client_command_context *cmd);
 
16398
+
 
16399
+struct command {
 
16400
+       const char *name;
 
16401
+       command_func_t *func;
 
16402
+};
 
16403
+
 
16404
+/* Register command. Given name parameter must be permanently stored until
 
16405
+   command is unregistered. */
 
16406
+void command_register(const char *name, command_func_t *func);
 
16407
+void command_unregister(const char *name);
 
16408
+
 
16409
+/* Register array of commands. */
 
16410
+void command_register_array(const struct command *cmdarr, unsigned int count);
 
16411
+void command_unregister_array(const struct command *cmdarr, unsigned int count);
 
16412
+
 
16413
+command_func_t *command_find(const char *name);
 
16414
+
 
16415
+void commands_init(void);
 
16416
+void commands_deinit(void);
 
16417
+
 
16418
+/* MANAGESIEVE commands: */
 
16419
+
 
16420
+/* Non-Authenticated State */
 
16421
+bool cmd_logout(struct client_command_context *cmd);
 
16422
+
 
16423
+bool cmd_capability(struct client_command_context *cmd);
 
16424
+
 
16425
+/* Authenticated State */
 
16426
+bool cmd_putscript(struct client_command_context *cmd);
 
16427
+bool cmd_getscript(struct client_command_context *cmd);
 
16428
+bool cmd_setactive(struct client_command_context *cmd);
 
16429
+bool cmd_deletescript(struct client_command_context *cmd);
 
16430
+bool cmd_listscripts(struct client_command_context *cmd);
 
16431
+bool cmd_havespace(struct client_command_context *cmd);
 
16432
+
 
16433
+
 
16434
+#endif
 
16435
diff -r 894f003d9f5f src/managesieve/common.h
 
16436
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
16437
+++ b/src/managesieve/common.h  Sun May 04 16:00:59 2008 +0200
 
16438
@@ -0,0 +1,38 @@
 
16439
+#ifndef __COMMON_H
 
16440
+#define __COMMON_H
 
16441
+
 
16442
+#include "lib.h"
 
16443
+#include "client.h"
 
16444
+
 
16445
+/* Disconnect client after idling this many seconds */
 
16446
+#define CLIENT_IDLE_TIMEOUT (60*30)
 
16447
+
 
16448
+/* If we can't send anything to client for this long, disconnect the client */
 
16449
+#define CLIENT_OUTPUT_TIMEOUT (5*60)
 
16450
+
 
16451
+/* Stop buffering more data into output stream after this many bytes */
 
16452
+#define CLIENT_OUTPUT_OPTIMAL_SIZE 2048
 
16453
+
 
16454
+/* Disconnect client when it sends too many bad commands in a row */
 
16455
+#define CLIENT_MAX_BAD_COMMANDS 20
 
16456
+
 
16457
+/* RFC-2683 recommends at least 8000 bytes. Some clients however don't
 
16458
+   break large message sets to multiple commands, so we're pretty liberal
 
16459
+   by default. */
 
16460
+#define DEFAULT_MANAGESIEVE_MAX_LINE_LENGTH 65536
 
16461
+
 
16462
+#define DEFAULT_MANAGESIEVE_IMPLEMENTATION_STRING PACKAGE
 
16463
+
 
16464
+enum client_workarounds {
 
16465
+  WORKAROUND_DELAY_NONE    = 0x00,
 
16466
+};
 
16467
+
 
16468
+extern struct ioloop *ioloop;
 
16469
+extern unsigned int managesieve_max_line_length;
 
16470
+extern const char *managesieve_implementation_string;
 
16471
+extern enum client_workarounds client_workarounds;
 
16472
+
 
16473
+//extern void (*hook_mail_storage_created)(struct sieve_storage *storage);
 
16474
+extern void (*hook_client_created)(struct client **client);
 
16475
+
 
16476
+#endif
 
16477
diff -r 894f003d9f5f src/managesieve/main.c
 
16478
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
 
16479
+++ b/src/managesieve/main.c    Sun May 04 16:00:59 2008 +0200
 
16480
@@ -0,0 +1,292 @@
 
16481
+#include "common.h"
 
16482
+#include "ioloop.h"
 
16483
+#include "network.h"
 
16484
+#include "ostream.h"
 
16485
+#include "str.h"
 
16486
+#include "lib-signals.h"
 
16487
+#include "restrict-access.h"
 
16488
+#include "fd-close-on-exec.h"
 
16489
+#include "process-title.h"
 
16490
+#include "randgen.h"
 
16491
+#include "module-dir.h"
 
16492
+#include "dict-client.h"
 
16493
+#include "commands.h"
 
16494
+#include "sieve-storage.h"
 
16495
+#include "sieve-implementation.h"
 
16496
+
 
16497
+#include <stdio.h>
 
16498
+#include <stdlib.h>
 
16499
+#include <unistd.h>
 
16500
+#include <syslog.h>
 
16501
+
 
16502
+#define IS_STANDALONE() \
 
16503
+        (getenv("LOGGED_IN") == NULL)
 
16504
+
 
16505
+#define CRITICAL_MSG \
 
16506
+  "Internal error occured. Refer to server log for more information."
 
16507
+#define CRITICAL_MSG_STAMP CRITICAL_MSG " [%Y-%m-%d %H:%M:%S]"
 
16508
+
 
16509
+struct client_workaround_list {
 
16510
+       const char *name;
 
16511
+       enum client_workarounds num;
 
16512
+};
 
16513
+
 
16514
+struct client_workaround_list client_workaround_list[] = {
 
16515
+       { NULL, 0 }
 
16516
+};
 
16517
+
 
16518
+struct ioloop *ioloop;
 
16519
+unsigned int managesieve_max_line_length;
 
16520
+const char *managesieve_implementation_string;
 
16521
+enum client_workarounds client_workarounds = 0;
 
16522
+static struct io *log_io = NULL;
 
16523
+
 
16524
+static char log_prefix[128]; /* syslog() needs this to be permanent */
 
16525
+
 
16526
+//void (*hook_mail_storage_created)(struct mail_storage *storage) = NULL;
 
16527
+void (*hook_client_created)(struct client **client) = NULL;
 
16528
+
 
16529
+static void sig_die(int signo, void *context __attr_unused__)
 
16530
+{
 
16531
+       /* warn about being killed because of some signal, except SIGINT (^C)
 
16532
+          which is too common at least while testing :) */
 
16533
+       if (signo != SIGINT)
 
16534
+               i_warning("Killed with signal %d", signo);
 
16535
+       io_loop_stop(ioloop);
 
16536
+}
 
16537
+
 
16538
+static void log_error_callback(void *context __attr_unused__)
 
16539
+{
 
16540
+       io_loop_stop(ioloop);
 
16541
+}
 
16542
+
 
16543
+static void parse_workarounds(void)
 
16544
+{
 
16545
+       struct client_workaround_list *list;
 
16546
+       const char *env, *const *str;
 
16547
+
 
16548
+       env = getenv("MANAGESIEVE_CLIENT_WORKAROUNDS");
 
16549
+       if (env == NULL)
 
16550
+               return;
 
16551
+
 
16552
+       for (str = t_strsplit_spaces(env, " ,"); *str != NULL; str++) {
 
16553
+               list = client_workaround_list;
 
16554
+               for (; list->name != NULL; list++) {
 
16555
+                       if (strcasecmp(*str, list->name) == 0) {
 
16556
+                               client_workarounds |= list->num;
 
16557
+                               break;
 
16558
+                       }
 
16559
+               }
 
16560
+               if (list->name == NULL)
 
16561
+                       i_fatal("Unknown client workaround: %s", *str);
 
16562
+       }
 
16563
+}
 
16564
+
 
16565
+static void open_logfile(void)
 
16566
+{
 
16567
+       const char *user;
 
16568
+
 
16569
+       if (getenv("LOG_TO_MASTER") != NULL) {
 
16570
+               i_set_failure_internal();
 
16571
+               return;
 
16572
+       }
 
16573
+
 
16574
+       if (getenv("LOG_PREFIX") != NULL)
 
16575
+               strocpy(log_prefix, getenv("LOG_PREFIX"), sizeof(log_prefix));
 
16576
+       else {
 
16577
+               user = getenv("USER");
 
16578
+               if (user == NULL) {
 
16579
+                       if (IS_STANDALONE())
 
16580
+                               user = getlogin();
 
16581
+                       if (user == NULL)
 
16582
+                               user = "??";
 
16583
+               }
 
16584
+               if (strlen(user) >= sizeof(log_prefix)-6) {     
 
16585
+                       /* quite a long user name, cut it */
 
16586
+                       user = t_strndup(user, sizeof(log_prefix)-6-2);
 
16587
+                       user = t_strconcat(user, "..", NULL);
 
16588
+               }
 
16589
+               i_snprintf(log_prefix, sizeof(log_prefix), "imap(%s): ", user);
 
16590
+       }
 
16591
+
 
16592
+       if (getenv("USE_SYSLOG") != NULL) {
 
16593
+               const char *env = getenv("SYSLOG_FACILITY");
 
16594
+               i_set_failure_syslog(log_prefix, LOG_NDELAY,
 
16595
+                                    env == NULL ? LOG_MAIL : atoi(env));
 
16596
+       } else {
 
16597
+               /* log to file or stderr */
 
16598
+               i_set_failure_file(getenv("LOGFILE"), log_prefix);
 
16599
+       }
 
16600
+
 
16601
+       if (getenv("INFOLOGFILE") != NULL)
 
16602
+               i_set_info_file(getenv("INFOLOGFILE"));
 
16603
+
 
16604
+       i_set_failure_timestamp_format(getenv("LOGSTAMP"));
 
16605
+}
 
16606
+
 
16607
+static void drop_privileges(void)
 
16608
+{
 
16609
+       const char *version;
 
16610
+
 
16611
+       version = getenv("DOVECOT_VERSION");
 
16612
+       if (version != NULL && strcmp(version, PACKAGE_VERSION) != 0) {
 
16613
+               i_fatal("Dovecot version mismatch: "
 
16614
+                       "Master is v%s, managesieve is v"PACKAGE_VERSION" "
 
16615
+                       "(if you don't care, set version_ignore=yes)", version);
 
16616
+       }
 
16617
+
 
16618
+       /* Log file or syslog opening probably requires roots */
 
16619
+       open_logfile();
 
16620
+
 
16621
+       /* Most likely needed. Have to open /dev/urandom before possible
 
16622
+          chrooting. */
 
16623
+       random_init();
 
16624
+
 
16625
+    restrict_access_by_env(!IS_STANDALONE());
 
16626
+}
 
16627
+
 
16628
+static void internal_error()
 
16629
+{
 
16630
+  struct tm *tm;
 
16631
+  char str[256];
 
16632
+
 
16633
+  tm = localtime(&ioloop_time);
 
16634
+
 
16635
+  printf("BYE \"%s\"\n",
 
16636
+    strftime(str, sizeof(str), CRITICAL_MSG_STAMP, tm) > 0 ?
 
16637
+    i_strdup(str) : i_strdup(CRITICAL_MSG));
 
16638
+}
 
16639
+
 
16640
+static void main_init(void)
 
16641
+{
 
16642
+       struct sieve_storage *storage;
 
16643
+       struct client *client;
 
16644
+       const char *user, *str, *sieve_storage, *mail;
 
16645
+
 
16646
+       lib_signals_init();
 
16647
+        lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
 
16648
+        lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL);
 
16649
+        lib_signals_ignore(SIGPIPE);
 
16650
+        lib_signals_set_handler(SIGALRM, FALSE, NULL, NULL);
 
16651
+
 
16652
+       user = getenv("USER");
 
16653
+       if (user == NULL) {
 
16654
+               if (IS_STANDALONE())
 
16655
+                       user = getlogin();
 
16656
+               if (user == NULL) {
 
16657
+                       internal_error();
 
16658
+                       i_fatal("USER environment missing");
 
16659
+               }
 
16660
+       }
 
16661
+
 
16662
+       if (getenv("DEBUG") != NULL) {
 
16663
+               const char *home;
 
16664
+
 
16665
+        home = getenv("HOME");
 
16666
+        i_info("Effective uid=%s, gid=%s, home=%s",
 
16667
+               dec2str(geteuid()), dec2str(getegid()),
 
16668
+               home != NULL ? home : "(none)");
 
16669
+       }
 
16670
+       
 
16671
+       if (getenv("STDERR_CLOSE_SHUTDOWN") != NULL) {
 
16672
+               /* If master dies, the log fd gets closed and we'll quit */
 
16673
+               log_io = io_add(STDERR_FILENO, IO_ERROR,
 
16674
+                               log_error_callback, NULL);
 
16675
+       }
 
16676
+
 
16677
+       sieve_init();
 
16678
+       sieve_set_implementation("cmu");
 
16679
+
 
16680
+       dict_client_register();
 
16681
+       clients_init();
 
16682
+       commands_init();
 
16683
+
 
16684
+       /* Settings */
 
16685
+       str = getenv("MANAGESIEVE_MAX_LINE_LENGTH");
 
16686
+       managesieve_max_line_length = str != NULL ?
 
16687
+               (unsigned int)strtoul(str, NULL, 10) :
 
16688
+               DEFAULT_MANAGESIEVE_MAX_LINE_LENGTH;
 
16689
+
 
16690
+       str = getenv("MANAGESIEVE_IMPLEMENTATION_STRING");
 
16691
+       managesieve_implementation_string = str != NULL ?
 
16692
+    str : DEFAULT_MANAGESIEVE_IMPLEMENTATION_STRING;
 
16693
+
 
16694
+       mail = getenv("MAIL"); 
 
16695
+       sieve_storage = getenv("SIEVE_STORAGE");
 
16696
+       if ( (sieve_storage == NULL || *sieve_storage == '\0') && 
 
16697
+               !(mail == NULL || *mail == '\0') ) { 
 
16698
+               storage = sieve_storage_create_from_mail(mail, user);
 
16699
+       } else 
 
16700
+               storage = sieve_storage_create(sieve_storage, user);
 
16701
+
 
16702
+       if (storage == NULL) { 
 
16703
+       internal_error();
 
16704
+
 
16705
+               /* failed */
 
16706
+               if (sieve_storage != NULL && *sieve_storage != '\0')   
 
16707
+                       i_fatal("Failed to create sieve storage with data: %s", sieve_storage);
 
16708
+               else if (mail != NULL && *mail != '\0')   
 
16709
+                       i_fatal("Failed to create sieve storage with mail-data: %s", mail);
 
16710
+               else {
 
16711
+                       const char *home;
 
16712
+           
 
16713
+                       home = getenv("HOME");
 
16714
+                       if (home == NULL) home = "not set";
 
16715
+           
 
16716
+                       i_fatal("SIEVE_STORAGE and MAIL environment missing and "
 
16717
+                               "autodetection failed (home %s)", home);
 
16718
+               }
 
16719
+       }
 
16720
+       
 
16721
+       parse_workarounds();
 
16722
+
 
16723
+       client = client_create(0, 1, storage);
 
16724
+       
 
16725
+       client_send_ok(client, "Logged in.");
 
16726
+}
 
16727
+
 
16728
+static void main_deinit(void)
 
16729
+{
 
16730
+       if (log_io != NULL)
 
16731
+               io_remove(&log_io);
 
16732
+       clients_deinit();
 
16733
+
 
16734
+       commands_deinit();
 
16735
+       dict_client_unregister();
 
16736
+       sieve_deinit();
 
16737
+       random_deinit();
 
16738
+
 
16739
+       lib_signals_deinit();
 
16740
+       closelog();
 
16741
+}
 
16742
+
 
16743
+int main(int argc __attr_unused__, char *argv[], char *envp[])
 
16744
+{
 
16745
+#ifdef DEBUG
 
16746
+       if (getenv("LOGGED_IN") != NULL && getenv("GDB") == NULL)
 
16747
+               fd_debug_verify_leaks(3, 1024);
 
16748
+#endif
 
16749
+       if (IS_STANDALONE() && getuid() == 0 &&
 
16750
+           net_getpeername(1, NULL, NULL) == 0) {
 
16751
+               printf("NO \"managesieve binary must not be started from "
 
16752
+                      "inetd, use managesieve-login instead.\"\n");
 
16753
+               return 1;
 
16754
+       }
 
16755
+
 
16756
+       /* NOTE: we start rooted, so keep the code minimal until
 
16757
+          restrict_access_by_env() is called */
 
16758
+       lib_init();
 
16759
+       drop_privileges();
 
16760
+
 
16761
+       process_title_init(argv, envp);
 
16762
+       ioloop = io_loop_create(system_pool);
 
16763
+
 
16764
+       main_init();
 
16765
+       io_loop_run(ioloop);
 
16766
+       main_deinit();
 
16767
+
 
16768
+       io_loop_destroy(&ioloop);
 
16769
+       lib_deinit();
 
16770
+
 
16771
+       return 0;
 
16772
+}
 
16773
diff -r 894f003d9f5f src/master/common.h
 
16774
--- a/src/master/common.h       Sun Mar 09 12:50:11 2008 +0200
 
16775
+++ b/src/master/common.h       Sun May 04 16:00:59 2008 +0200
 
16776
@@ -17,6 +17,7 @@ enum process_type {
 
16777
        PROCESS_TYPE_SSL_PARAM,
 
16778
        PROCESS_TYPE_DICT,
 
16779
 
 
16780
+       PROCESS_TYPE_MANAGESIEVE,
 
16781
        PROCESS_TYPE_MAX
 
16782
 };
 
16783
 
 
16784
diff -r 894f003d9f5f src/master/login-process.c
 
16785
--- a/src/master/login-process.c        Sun Mar 09 12:50:11 2008 +0200
 
16786
+++ b/src/master/login-process.c        Sun May 04 16:00:59 2008 +0200
 
16787
@@ -67,8 +67,20 @@ static void login_group_create(struct se
 
16788
        group = i_new(struct login_group, 1);
 
16789
        group->refcount = 1;
 
16790
        group->set = set;
 
16791
-       group->process_type = set->protocol == MAIL_PROTOCOL_IMAP ?
 
16792
-               PROCESS_TYPE_IMAP : PROCESS_TYPE_POP3;
 
16793
+
 
16794
+       switch ( set->protocol ) {
 
16795
+               case MAIL_PROTOCOL_IMAP:
 
16796
+                       group->process_type = PROCESS_TYPE_IMAP;
 
16797
+                       break;
 
16798
+               case MAIL_PROTOCOL_POP3:
 
16799
+                       group->process_type = PROCESS_TYPE_POP3;
 
16800
+                       break;
 
16801
+               case MAIL_PROTOCOL_MANAGESIEVE:
 
16802
+                       group->process_type = PROCESS_TYPE_MANAGESIEVE;
 
16803
+                       break;
 
16804
+               default:
 
16805
+                       i_unreached();
 
16806
+       }
 
16807
 
 
16808
        group->next = login_groups;
 
16809
        login_groups = group;
 
16810
@@ -222,6 +234,8 @@ static void login_process_groups_create(
 
16811
                        login_group_create(server->imap);
 
16812
                if (server->pop3 != NULL)
 
16813
                        login_group_create(server->pop3);
 
16814
+               if (server->managesieve != NULL)
 
16815
+                       login_group_create(server->managesieve);
 
16816
        }
 
16817
 }
 
16818
 
 
16819
@@ -283,6 +297,8 @@ static bool login_process_read_group(str
 
16820
                        protocol = MAIL_PROTOCOL_IMAP;
 
16821
                else if (strcmp(proto, "pop3") == 0)
 
16822
                        protocol = MAIL_PROTOCOL_POP3;
 
16823
+               else if (strcmp(proto, "managesieve") == 0)
 
16824
+                       protocol = MAIL_PROTOCOL_MANAGESIEVE;
 
16825
                else {
 
16826
                        i_error("login: Unknown protocol '%s'", proto);
 
16827
                        return FALSE;
 
16828
@@ -580,6 +596,9 @@ static void login_process_init_env(struc
 
16829
                                    *set->imap_capability != '\0' ?
 
16830
                                    set->imap_capability :
 
16831
                                    set->imap_generated_capability, NULL));
 
16832
+       } else if (group->process_type == PROCESS_TYPE_MANAGESIEVE) {
 
16833
+               env_put(t_strconcat("MANAGESIEVE_IMPLEMENTATION_STRING=",
 
16834
+                       set->managesieve_implementation_string, NULL));
 
16835
        }
 
16836
 }
 
16837
 
 
16838
diff -r 894f003d9f5f src/master/mail-process.c
 
16839
--- a/src/master/mail-process.c Sun Mar 09 12:50:11 2008 +0200
 
16840
+++ b/src/master/mail-process.c Sun May 04 16:00:59 2008 +0200
 
16841
@@ -231,6 +231,25 @@ mail_process_set_environment(struct sett
 
16842
                            set->pop3_client_workarounds, NULL));
 
16843
        env_put(t_strconcat("POP3_LOGOUT_FORMAT=",
 
16844
                            set->pop3_logout_format, NULL));
 
16845
+
 
16846
+       env_put(t_strdup_printf("MANAGESIEVE_MAX_LINE_LENGTH=%u",
 
16847
+                               set->managesieve_max_line_length));
 
16848
+       env_put(t_strconcat("MANAGESIEVE_IMPLEMENTATION_STRING=",
 
16849
+        set->managesieve_implementation_string, NULL));
 
16850
+
 
16851
+       /* Set sieve environment 
 
16852
+        *   FIXME: Currently just uses the expand_mail_env function to 
 
16853
+        *   substitute variables and home dir. Technically, that function
 
16854
+        *   is not meant for the sieve implementation.  
 
16855
+        */
 
16856
+       if ( set->sieve_storage != NULL ) {
 
16857
+               env_put(t_strconcat("SIEVE_STORAGE=",
 
16858
+               expand_mail_env(set->sieve_storage, var_expand_table), NULL));
 
16859
+       }
 
16860
+       if (set->sieve != NULL) {
 
16861
+               env_put(t_strconcat("SIEVE=",
 
16862
+                       expand_mail_env(set->sieve, var_expand_table), NULL));
 
16863
+       }
 
16864
 
 
16865
        if (set->mail_save_crlf)
 
16866
                env_put("MAIL_SAVE_CRLF=1");
 
16867
@@ -348,6 +367,8 @@ void mail_process_exec(const char *proto
 
16868
                        set = server->imap;
 
16869
                else if (strcmp(protocol, "pop3") == 0)
 
16870
                        set = server->pop3;
 
16871
+               else if (strcmp(protocol, "managesieve") == 0)
 
16872
+                       set = server->managesieve;
 
16873
                else
 
16874
                        i_fatal("Unknown protocol: '%s'", protocol);
 
16875
                executable = set->mail_executable;
 
16876
diff -r 894f003d9f5f src/master/main.c
 
16877
--- a/src/master/main.c Sun Mar 09 12:50:11 2008 +0200
 
16878
+++ b/src/master/main.c Sun May 04 16:00:59 2008 +0200
 
16879
@@ -33,7 +33,8 @@ const char *process_names[PROCESS_TYPE_M
 
16880
        "imap",
 
16881
        "pop3",
 
16882
        "ssl-build-param",
 
16883
-       "dict"
 
16884
+       "dict",
 
16885
+        "managesieve"
 
16886
 };
 
16887
 
 
16888
 static const char *configfile = SYSCONFDIR "/" PACKAGE ".conf";
 
16889
@@ -241,6 +242,7 @@ static void sigchld_handler(int signo __
 
16890
                        break;
 
16891
                case PROCESS_TYPE_IMAP:
 
16892
                case PROCESS_TYPE_POP3:
 
16893
+               case PROCESS_TYPE_MANAGESIEVE:
 
16894
                        mail_process_destroyed(pid);
 
16895
                        break;
 
16896
                case PROCESS_TYPE_SSL_PARAM:
 
16897
@@ -354,6 +356,10 @@ static void check_conflicts(const struct
 
16898
                        check_conflicts_set(server->pop3, ip, port,
 
16899
                                            "pop3", proto);
 
16900
                }
 
16901
+               if (server->managesieve != NULL) {
 
16902
+                       check_conflicts_set(server->managesieve, ip, port,
 
16903
+                                           "managesieve", proto);
 
16904
+               }
 
16905
        }
 
16906
 }
 
16907
 
 
16908
@@ -364,13 +370,31 @@ static void listen_protocols(struct sett
 
16909
        unsigned int port;
 
16910
        int *fd, i;
 
16911
 
 
16912
-       set->listen_port = set->protocol == MAIL_PROTOCOL_IMAP ? 143 : 110;
 
16913
+       switch (set->protocol) {
 
16914
+       case MAIL_PROTOCOL_IMAP:
 
16915
+               set->listen_port = 143;
 
16916
 #ifdef HAVE_SSL
 
16917
-       set->ssl_listen_port = set->protocol == MAIL_PROTOCOL_IMAP ? 993 : 995;
 
16918
+               set->ssl_listen_port = 993;
 
16919
 #else
 
16920
-       set->ssl_listen_port = 0;
 
16921
-#endif
 
16922
-
 
16923
+               set->ssl_listen_port = 0;
 
16924
+#endif
 
16925
+               break;
 
16926
+       case MAIL_PROTOCOL_POP3:
 
16927
+               set->listen_port = 110;
 
16928
+#ifdef HAVE_SSL
 
16929
+               set->ssl_listen_port = 995;
 
16930
+#else
 
16931
+               set->ssl_listen_port = 0;
 
16932
+#endif
 
16933
+               break;
 
16934
+       case MAIL_PROTOCOL_MANAGESIEVE:
 
16935
+               set->listen_port = 2000;
 
16936
+               set->ssl_listen_port = 0;
 
16937
+               break;
 
16938
+       default:
 
16939
+               i_unreached();
 
16940
+       }
 
16941
 
16942
        /* resolve */
 
16943
        resolve_ip("listen", set->listen, &set->listen_ip, &set->listen_port);
 
16944
        if (!set->ssl_disable) {
 
16945
@@ -413,6 +437,12 @@ static void listen_protocols(struct sett
 
16946
                                port = set->ssl_listen_port;
 
16947
                                ip = &set->ssl_listen_ip;
 
16948
                        }
 
16949
+               } else if (strcasecmp(*proto, "managesieve") == 0) {
 
16950
+                       if (set->protocol == MAIL_PROTOCOL_MANAGESIEVE) {
 
16951
+                               fd = &set->listen_fd;
 
16952
+                               port = set->listen_port;
 
16953
+                               ip = &set->listen_ip;
 
16954
+                       }
 
16955
                } else {
 
16956
                        i_fatal("Unknown protocol %s", *proto);
 
16957
                }
 
16958
@@ -466,12 +496,14 @@ static void listen_fds_open(bool retry)
 
16959
 static void listen_fds_open(bool retry)
 
16960
 {
 
16961
        struct server_settings *server;
 
16962
-
 
16963
+  
 
16964
        for (server = settings_root; server != NULL; server = server->next) {
 
16965
                if (server->imap != NULL)
 
16966
                        listen_protocols(server->imap, retry);
 
16967
                if (server->pop3 != NULL)
 
16968
                        listen_protocols(server->pop3, retry);
 
16969
+               if (server->managesieve != NULL)
 
16970
+                       listen_protocols(server->managesieve, retry);
 
16971
        }
 
16972
 }
 
16973
 
 
16974
@@ -494,6 +526,11 @@ static void listen_fds_close(struct serv
 
16975
                            close(server->pop3->ssl_listen_fd) < 0)
 
16976
                                i_error("close(pop3.ssl_listen_fd) failed: %m");
 
16977
                }
 
16978
+               if (server->managesieve != NULL) {
 
16979
+                       if (server->managesieve->listen_fd != null_fd &&
 
16980
+                           close(server->managesieve->listen_fd) < 0)
 
16981
+                               i_error("close(managesieve.listen_fd) failed: %m");
 
16982
+               }
 
16983
        }
 
16984
 }
 
16985
 
 
16986
@@ -516,6 +553,8 @@ static bool have_stderr(struct server_se
 
16987
                if (server->imap != NULL && have_stderr_set(server->imap))
 
16988
                        return TRUE;
 
16989
                if (server->pop3 != NULL && have_stderr_set(server->pop3))
 
16990
+                       return TRUE;
 
16991
+               if (server->managesieve != NULL && have_stderr_set(server->managesieve))
 
16992
                        return TRUE;
 
16993
 
 
16994
                server = server->next;
 
16995
diff -r 894f003d9f5f src/master/master-settings-defs.c
 
16996
--- a/src/master/master-settings-defs.c Sun Mar 09 12:50:11 2008 +0200
 
16997
+++ b/src/master/master-settings-defs.c Sun May 04 16:00:59 2008 +0200
 
16998
@@ -115,5 +115,13 @@ static struct setting_def setting_defs[]
 
16999
        DEF(SET_STR, pop3_client_workarounds),
 
17000
        DEF(SET_STR, pop3_logout_format),
 
17001
 
 
17002
+       /* managesieve */
 
17003
+       DEF(SET_INT, managesieve_max_line_length),
 
17004
+       DEF(SET_STR, managesieve_implementation_string),
 
17005
+
 
17006
+       /* sieve */
 
17007
+       DEF(SET_STR, sieve_storage),
 
17008
+       DEF(SET_STR, sieve),
 
17009
+
 
17010
        { 0, NULL, 0 }
 
17011
 };
 
17012
diff -r 894f003d9f5f src/master/master-settings.c
 
17013
--- a/src/master/master-settings.c      Sun Mar 09 12:50:11 2008 +0200
 
17014
+++ b/src/master/master-settings.c      Sun May 04 16:00:59 2008 +0200
 
17015
@@ -269,6 +269,14 @@ struct settings default_settings = {
 
17016
        MEMBER(pop3_client_workarounds) "",
 
17017
        MEMBER(pop3_logout_format) "top=%t/%p, retr=%r/%b, del=%d/%m, size=%s",
 
17018
 
 
17019
+       /* managesieve */
 
17020
+       MEMBER(managesieve_max_line_length) 65536,
 
17021
+       MEMBER(managesieve_implementation_string) PACKAGE,
 
17022
+
 
17023
+       /* sieve */
 
17024
+       MEMBER(sieve_storage) "",
 
17025
+       MEMBER(sieve) NULL,
 
17026
+
 
17027
        /* .. */
 
17028
        MEMBER(listen_fd) -1,
 
17029
        MEMBER(ssl_listen_fd) -1
 
17030
@@ -425,6 +433,8 @@ static bool auth_settings_verify(struct 
 
17031
                        auth->parent->pop3->ssl_verify_client_cert = TRUE;
 
17032
                if (auth->parent->imap != NULL)
 
17033
                        auth->parent->imap->ssl_verify_client_cert = TRUE;
 
17034
+               if (auth->parent->managesieve != NULL)
 
17035
+                       auth->parent->managesieve->ssl_verify_client_cert = TRUE;
 
17036
        }
 
17037
 
 
17038
        for (s = auth->sockets; s != NULL; s = s->next) {
 
17039
@@ -475,8 +485,11 @@ static bool settings_is_active(struct se
 
17040
        if (set->protocol == MAIL_PROTOCOL_IMAP) {
 
17041
                if (strstr(set->protocols, "imap") == NULL)
 
17042
                        return FALSE;
 
17043
+       } else if (set->protocol == MAIL_PROTOCOL_POP3) {
 
17044
+               if (strstr(set->protocols, "pop3") == NULL)
 
17045
+                       return FALSE;
 
17046
        } else {
 
17047
-               if (strstr(set->protocols, "pop3") == NULL)
 
17048
+               if (strstr(set->protocols, "managesieve") == NULL)
 
17049
                        return FALSE;
 
17050
        }
 
17051
 
 
17052
@@ -1081,7 +1094,7 @@ static const char *parse_setting(const c
 
17053
 
 
17054
        if (strcmp(key, "login") == 0) {
 
17055
                i_warning("Ignoring deprecated 'login' section handling. "
 
17056
-                         "Use protocol imap/pop3 { .. } instead. "
 
17057
+                         "Use protocol imap/pop3/managesieve { .. } instead. "
 
17058
                          "Some settings may have been read incorrectly.");
 
17059
                return NULL;
 
17060
        }
 
17061
@@ -1104,6 +1117,15 @@ static const char *parse_setting(const c
 
17062
                        error = parse_setting_from_defs(settings_pool,
 
17063
                                                        setting_defs,
 
17064
                                                        ctx->server->pop3,
 
17065
+                                                       key, value);
 
17066
+               }
 
17067
+
 
17068
+               if (error == NULL &&
 
17069
+                   (ctx->protocol == MAIL_PROTOCOL_ANY ||
 
17070
+                    ctx->protocol == MAIL_PROTOCOL_MANAGESIEVE)) {
 
17071
+                       error = parse_setting_from_defs(settings_pool,
 
17072
+                                                       setting_defs,
 
17073
+                                                       ctx->server->managesieve,
 
17074
                                                        key, value);
 
17075
                }
 
17076
 
 
17077
@@ -1165,6 +1187,13 @@ static const char *parse_setting(const c
 
17078
                        array_append(&ctx->server->pop3->plugin_envs,
 
17079
                                     &value, 1);
 
17080
                }
 
17081
+               if (ctx->protocol == MAIL_PROTOCOL_ANY ||
 
17082
+                   ctx->protocol == MAIL_PROTOCOL_MANAGESIEVE) {
 
17083
+                       array_append(&ctx->server->managesieve->plugin_envs, &key, 1);
 
17084
+                       array_append(&ctx->server->managesieve->plugin_envs,
 
17085
+                                    &value, 1);
 
17086
+               }
 
17087
+
 
17088
                return NULL;
 
17089
        }
 
17090
 
 
17091
@@ -1174,7 +1203,8 @@ static struct server_settings *
 
17092
 static struct server_settings *
 
17093
 create_new_server(const char *name,
 
17094
                  struct settings *imap_defaults,
 
17095
-                 struct settings *pop3_defaults)
 
17096
+                 struct settings *pop3_defaults,
 
17097
+                 struct settings *managesieve_defaults)
 
17098
 {
 
17099
        struct server_settings *server;
 
17100
 
 
17101
@@ -1182,16 +1212,20 @@ create_new_server(const char *name,
 
17102
        server->name = p_strdup(settings_pool, name);
 
17103
        server->imap = p_new(settings_pool, struct settings, 1);
 
17104
        server->pop3 = p_new(settings_pool, struct settings, 1);
 
17105
+       server->managesieve = p_new(settings_pool, struct settings, 1);
 
17106
        server->auth_defaults = default_auth_settings;
 
17107
 
 
17108
        *server->imap = *imap_defaults;
 
17109
        *server->pop3 = *pop3_defaults;
 
17110
+       *server->managesieve = *managesieve_defaults;
 
17111
 
 
17112
        ARRAY_CREATE(&server->dicts, settings_pool, const char *, 4);
 
17113
        ARRAY_CREATE(&server->imap->plugin_envs, settings_pool,
 
17114
                     const char *, 8);
 
17115
        ARRAY_CREATE(&server->pop3->plugin_envs, settings_pool,
 
17116
                     const char *, 8);
 
17117
+       ARRAY_CREATE(&server->managesieve->plugin_envs, settings_pool,
 
17118
+                    const char *, 8);
 
17119
 
 
17120
        server->imap->server = server;
 
17121
        server->imap->protocol = MAIL_PROTOCOL_IMAP;
 
17122
@@ -1205,6 +1239,12 @@ create_new_server(const char *name,
 
17123
        server->pop3->mail_executable = PKG_LIBEXECDIR"/pop3";
 
17124
        server->pop3->mail_plugin_dir = MODULEDIR"/pop3";
 
17125
 
 
17126
+       server->managesieve->server = server;
 
17127
+       server->managesieve->protocol = MAIL_PROTOCOL_MANAGESIEVE;
 
17128
+       server->managesieve->login_executable = PKG_LIBEXECDIR"/managesieve-login";
 
17129
+       server->managesieve->mail_executable = PKG_LIBEXECDIR"/managesieve";
 
17130
+       server->managesieve->mail_plugin_dir = MODULEDIR"/managesieve";
 
17131
+  
 
17132
        return server;
 
17133
 }
 
17134
 
 
17135
@@ -1248,8 +1288,8 @@ static bool parse_section(const char *ty
 
17136
 
 
17137
                ctx->type = SETTINGS_TYPE_SERVER;
 
17138
                ctx->server = create_new_server(name, ctx->server->imap,
 
17139
-                                               ctx->server->pop3);
 
17140
-                server = ctx->root;
 
17141
+                                               ctx->server->pop3, ctx->server->managesieve);
 
17142
+               server = ctx->root;
 
17143
                while (server->next != NULL)
 
17144
                        server = server->next;
 
17145
                server->next = ctx->server;
 
17146
@@ -1270,6 +1310,8 @@ static bool parse_section(const char *ty
 
17147
                        ctx->protocol = MAIL_PROTOCOL_POP3;
 
17148
                else if (strcmp(name, "lda") == 0)
 
17149
                        ctx->protocol = MAIL_PROTOCOL_LDA;
 
17150
+               else if (strcmp(name, "managesieve") == 0)
 
17151
+                       ctx->protocol = MAIL_PROTOCOL_MANAGESIEVE;
 
17152
                else {
 
17153
                        *errormsg = "Unknown protocol name";
 
17154
                        return FALSE;
 
17155
@@ -1380,7 +1422,7 @@ bool master_settings_read(const char *pa
 
17156
        ctx.protocol = MAIL_PROTOCOL_ANY;
 
17157
        ctx.server = ctx.root =
 
17158
                create_new_server("default",
 
17159
-                                 &default_settings, &default_settings);
 
17160
+                                 &default_settings, &default_settings, &default_settings);
 
17161
        ctx.auth = &ctx.server->auth_defaults;
 
17162
 
 
17163
        if (!settings_read(path, NULL, parse_setting, parse_section, &ctx))
 
17164
@@ -1397,7 +1439,9 @@ bool master_settings_read(const char *pa
 
17165
 
 
17166
        if (!nochecks && !nofixes) {
 
17167
                ctx.root->defaults = settings_is_active(ctx.root->imap) ?
 
17168
-                       ctx.root->imap : ctx.root->pop3;
 
17169
+                       ctx.root->imap : 
 
17170
+                       (settings_is_active(ctx.root->pop3) ? 
 
17171
+                               ctx.root->pop3 : ctx.root->managesieve);
 
17172
 
 
17173
                path = t_strconcat(ctx.root->defaults->base_dir,
 
17174
                                   "/master.pid", NULL);
 
17175
@@ -1407,7 +1451,8 @@ bool master_settings_read(const char *pa
 
17176
        prev = NULL;
 
17177
        for (server = ctx.root; server != NULL; server = server->next) {
 
17178
                if ((*server->imap->protocols == '\0' ||
 
17179
-                    *server->pop3->protocols == '\0') && !nochecks) {
 
17180
+                    *server->pop3->protocols == '\0' ||
 
17181
+                    *server->managesieve->protocols == '\0') && !nochecks) {
 
17182
                        i_error("No protocols given in configuration file");
 
17183
                        return FALSE;
 
17184
                }
 
17185
@@ -1437,6 +1482,15 @@ bool master_settings_read(const char *pa
 
17186
                                server->defaults = server->pop3;
 
17187
                }
 
17188
 
 
17189
+               if (!settings_is_active(server->managesieve) && !nochecks)
 
17190
+                       server->managesieve = NULL;
 
17191
+               else {
 
17192
+                       if (!settings_fix(server->managesieve, nochecks, nofixes))
 
17193
+                               return FALSE;
 
17194
+                       if (server->defaults == NULL)
 
17195
+                               server->defaults = server->managesieve;
 
17196
+               }
 
17197
+
 
17198
                if (server->defaults == NULL) {
 
17199
                        if (prev == NULL)
 
17200
                                ctx.root = server->next;
 
17201
@@ -1653,8 +1707,8 @@ static void dict_settings_dump(const str
 
17202
 
 
17203
 void master_settings_dump(struct server_settings *set, bool nondefaults)
 
17204
 {
 
17205
-       const void *sets[4];
 
17206
-       const char *set_names[4];
 
17207
+       const void *sets[5];
 
17208
+       const char *set_names[5];
 
17209
        unsigned int count;
 
17210
 
 
17211
        sets[0] = &default_settings;
 
17212
@@ -1673,6 +1727,11 @@ void master_settings_dump(struct server_
 
17213
                sets[count] = set->pop3;
 
17214
                set_names[count] = "pop3";
 
17215
                count++;
 
17216
+       }       
 
17217
+       if (set->managesieve != NULL) {
 
17218
+               sets[count] = set->managesieve;
 
17219
+               set_names[count] = "managesieve";
 
17220
+               count++;
 
17221
        }
 
17222
        settings_dump(setting_defs, sets, set_names, count, nondefaults, 0);
 
17223
        namespace_settings_dump(set->namespaces, nondefaults);
 
17224
diff -r 894f003d9f5f src/master/master-settings.h
 
17225
--- a/src/master/master-settings.h      Sun Mar 09 12:50:11 2008 +0200
 
17226
+++ b/src/master/master-settings.h      Sun May 04 16:00:59 2008 +0200
 
17227
@@ -4,10 +4,11 @@
 
17228
 #include "network.h"
 
17229
 
 
17230
 enum mail_protocol {
 
17231
-        MAIL_PROTOCOL_ANY,
 
17232
-        MAIL_PROTOCOL_IMAP,
 
17233
+       MAIL_PROTOCOL_ANY,
 
17234
+       MAIL_PROTOCOL_IMAP,
 
17235
        MAIL_PROTOCOL_POP3,
 
17236
-       MAIL_PROTOCOL_LDA
 
17237
+       MAIL_PROTOCOL_LDA,
 
17238
+       MAIL_PROTOCOL_MANAGESIEVE
 
17239
 };
 
17240
 
 
17241
 struct settings {
 
17242
@@ -123,6 +124,14 @@ struct settings {
 
17243
        const char *pop3_client_workarounds;
 
17244
        const char *pop3_logout_format;
 
17245
 
 
17246
+       /* managesieve */
 
17247
+       unsigned int managesieve_max_line_length;
 
17248
+       const char *managesieve_implementation_string;
 
17249
+
 
17250
+       /* sieve */
 
17251
+       const char *sieve_storage;
 
17252
+       const char *sieve;
 
17253
+
 
17254
        /* .. */
 
17255
        int listen_fd, ssl_listen_fd;
 
17256
 
 
17257
@@ -231,9 +240,10 @@ struct server_settings {
 
17258
        struct settings *defaults;
 
17259
        struct settings *imap;
 
17260
        struct settings *pop3;
 
17261
+       struct settings *managesieve;
 
17262
        struct auth_settings *auths;
 
17263
        struct auth_settings auth_defaults;
 
17264
-        struct namespace_settings *namespaces;
 
17265
+       struct namespace_settings *namespaces;
 
17266
 
 
17267
        array_t ARRAY_DEFINE(dicts, const char *);
 
17268